技术小记4(C++)

 1.减少依赖
Handle类,即通过包含来实现功能


class CPerson
{
 public:
   void func1()
   {
       pImpl->func1();
    }


private:
   CPersonImpl* pImpl;
};


接口类,即通过继承来实现功能


class IPerson
{
  public:
   virtual void IFunc1() const = 0;
};


class CPerson : public IPerson
{
   public:
     void IFunc1()
     {}
    
     static std::tr1::shared_ptr<Person> Create(...){} //这种类一般会有一个工厂类
}


为减少依赖,为头文件和声明分别提供头文件,看清楚了,都写在头文件里面

 typedef 不支持提前声明


2.用宏时,可能会产生意想不到的错误,
  对于 function-like macros(类似函数的宏),用 inline functions(内联函数)取代 #defines


3.不用初始化列表时,成员变量:先调用default constructor, 后调用copy assignment constructor
用初始化列表就只有一个copy constructor


4.析构函数应该永远都不抛出异常,如果要对这个异常做出回应,最好另外提供一个接口来释放资源


5.不是设计用来作为 base classes(基类)或不是设计用于 polymorphically(多态)的 classes(类)就不应该声明 virtual destructor


(虚拟析构函数)。


6. assignment operators(赋值运算符)返回一个 reference to *this(引向 *this 的引用)。


7.拷贝函数应该保证拷贝一个对象的所有数据成员以及所有的基类部分


8.避免返回堆栈上的指针,如
const Rational& operator*(const Rational& lhs,   // warning! more bad
                          const Rational& rhs)   // code!
{
  Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
  return *result;
}


Rational w, x, y, z;


w = x * y * z;
此时,将会发生资源泄漏


const Rational& operator*(const Rational& lhs,    // warning! yet more
                          const Rational& rhs)    // bad code!
{
  static Rational result;             // static object to which a
                                      // reference will be returned


  result = ... ;                      // multiply lhs by rhs and put the
                                      // product inside result
  return result;
}


Rational a, b, c, d;
if ((a * b) == (c * d))  //此时条件永远为真
{}
所以,不要轻易返回static对象的引用


8. 函数声明类型不同的含义:

1.simple virtual function : 继承一个接口同时可以作为缺省实现

如果不想让继承类有一个不知道怎么来的默认实现,用 “2”中的方法,同时另外实现一个non-virtual函数作为缺省实现

2.pure virtual function :  纯继承接口

3.non-virutal function : 继承一个强制实现


9 inline

记住,inline 是向编译器发出的一个请求,而不是一个命令。这个请求能够以显式的或隐式的方式提出。

①隐式的方法就是在一个类定义的内部定义一个函数:

class Person {
public:
  ...
  int age() const { return theAge; }    // an implicit inline request: age is
  ...                                   // defined in a class definition

private:
  int theAge;
};

显式地声明一个 inline函数的方法是在它的声明之前加上inline关键字


inline函数一般必须在头文件内,因为大多数构建环境在编译期间进行 inline化。为了用被调用函数的函数本体替换一个函数调用,编译器必须知道函数看起来像什么样子


模板一般在头文件内,因为编译器需要知道一个模板看起来像什么以便用到它时对它进行实例化。(同样,也不是全部如此。一些构建环境可以在连接期间进行模板实例化。然而,编译期实例化更为普遍

10.

  • 绝不要重定义一个 inherited default parameter value(通过继承得到的缺省参数值),因为 default parameter value(缺省参数值)是 statically bound(静态绑定),而 virtual functions ——应该是你可以 overriding(覆盖)的仅有的函数——是 dynamically bound(动态绑定)。

11.

  private继承不允许从继承类到基类的转换

private inheritance(私有继承)意味着 is-implemented-in-terms-of(是根据……实现的)的事实有一点混乱,因为 Item 38 指出 composition(复合)也有同样的含义。你怎么预先在它们之间做出选择呢?答案很简单:只要你能就用 composition(复合),只有在绝对必要的时候才用 private inheritance(私有继承)。什么时候是绝对必要呢?主要是当 protected members(保护成员)和/或 virtual functions(虚拟函数)掺和进来的时候


12.

用传引用给 const 取代传值。典型情况下它更高效而且可以避免切断问题。

·    这条规则并不适用于内建类型及 STL 中的迭代器和函数对象类型。对于它们,传值通常更合适。


13.

·operator>>和operator<<决不能是成员函数。如果f是operator>>或operator<<,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。

·只有非成员函数对最左边的参数进行类型转换。如果f需要对最左边的参数进行类型转换,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。


/*********************************************************************************************************************************************************************/

1.在声明一个函数时,如果用到某个类,是绝对不需要这个类的定义的,即使函数是通过传值来传递和返回这个类:


方式①
/********test.h******/
Date returnADate()
{
Date d;
return d;
}




/********Datedef.h******/
class Date
{
public:
int GetTime()
{
return 107;
}
};


/********main.cpp******/
#include "Datedef.h"  //注意顺序,否则不能编译
#include "test.h"


int _tmain(int argc, _TCHAR* argv[])
{
Date d = returnADate();
std::cout << d.GetTime() << std::endl;
return 0;
}


这样,只改变Date的定义时,tset.h不会被编译。


方式②


/*******test.h******/
class Date;
Date returnADate();




/********DateDef.h 跟上面一样******/


/********main.cpp******/
#include "test.h"
#include "Datedef.h" //这的顺序跟上面不一样


Date returnADate()
{
Date d;
return d;
}


int _tmain(int argc, _TCHAR* argv[])
{
Date d = returnADate();
std::cout << d.GetTime() << std::endl;
return 0;
}


2.
只能定义成宏使用,不能直接在函数里面使用
#define T(X) #X
#define T_Link(X, Y) X##Y
#define T_dot(X) #@X
class CA
{};


void function()
{}


int _tmain(int argc, _TCHAR* argv[])
{
std::cout << T(CA) << std::endl;
std::cout << T(function) << std::endl;
std::cout << T_Link(12, 3) << std::endl;
std::cout << T_dot(6) << std::endl;
}


3.取随机数
int random = rand() % 100;


4.通过extern使用全局变量时,这个变量必须是在CPP里面定义的


5.指针数组(这个不同于2维数组,二维数组的列是固定的)
int a1[2] = {1, 2};
int a2[3] = {11, 12, 13};
int a3[4] = {110, 120, 130, 140};
int* pArray[3] = {a1, a2, a3};


int** ppArray = pArray;


std::cout << (pArray)[1][1] << std::endl;


函数数组:


 int (*pfn[3])(int, int);


int Add(int one, int two)
{
return( one + two );
}


int Sub(int one, int two)
{
return ( one - two );
}


int Div(int one, int two)
{
return one/two;
}


int _tmain(int argc, _TCHAR* argv[])
{


pfn[0] = Add;
pfn[1] = Sub;
pfn[2] = Div;


for( int i = 0; i < 3; i++ )
{
std::cout << pfn[i](20, 10) << std::endl;
}
}


6.含有虚函数的类对象不能用memset初始化

你可能感兴趣的:(技术小记4(C++))