new operator申请内存,并调用构造函数;
而operator new只申请内存;
new operator会调用operator new来申请内存;operator new可以重写或重载;
placement new
exception specifications
void f1(); //该函数可能掷出任何类型的exception
void f2() throw(int);//该函数只掷出型别为int的exception
void f3() throw();//该函数不掷出任何exception
条款19:了解临时对象的来源
一是函数调用时参数的隐式类型转换;(如果参数类型是reference-to-non-const 时,不会进行隐式类型转换,因为这类函数会对实参进行修改)
二是当函数返回对象时。
C++真正所谓的临时对象是不可见的——只要产生一个 non-heap object 而没有为它命名,就产生了一个临时对象。它一般产生于两个地方:一是函数参数的隐式类型转换,二是函数返回对象时。 任何时候,只要你看到一个 reference-to-const 参数,就极可能会有一个临时对象被产生出来绑定至该参数上;任何时候,只要你看到函数返回一个对象,就会产生临时对象(并于稍后销毁)。
虚函数表vtbl(通常是“函数指针”数组,某些编译器可能以“函数指针”链表),一个类一份;
虚函数指针vptr,每个对象一个,和该对象的数据成员一起组成该对象,虚函数指针指向对象所属类的虚函数表。
看这个调用:pC1->f1();
如果函数f1的虚函数表vtbl索引是i,则这个调用产生的代码将是:
(*pC1->vptr[i])(pC1);//调用pC1->vptr所指之vtbl的第i个元素所指函数。
特别注意,(*pC1->vptr[i])(pC1),此处pC1被传给该函数作为this指针之用。结合下面的static成员函数加深对this指针的理解:
static成员函数
static成员是类的组成部分并不是任何对象的组成部分,因此,static成员函数没有this指针。我们知道,一般而言,类中的成员函数具有一个附加的隐含实参,即指向该类对象的一个指针。这个隐含实参命名为this。作用(只是参考别人的回答):1, 类似于namespace, 可以防止名字冲突。2, 可以有访问权限控制. 比如非public的static成员仅能在本类/子类的内部访问。
25、将 constructor 和 non-member functions 虚化
具体参见收藏的读书笔记。
static数据成员不能在类的定义区初始化,因此通常在某个实现文件中对它进行初始化;但新加入的C++特性允许对static const成员(必须为整形变量)进行初始化。
在派生类中使用using声明,使基类的成员可见,可以改变派生类对基类成员的访问权限。
隐式类型转换形式:operator T*();
单一自变量构造函数也可以作为类型转换操作符使用:T1(const T2* t2);
这两个都可能在函数调用时进行参数类型转换,但不能需要两次转换。
在智能指针中,由于其实现其实是模板类,因此基类和派生类、普通类型和该类型的const类型的智能指针是完全不同的类型,因此如果需要这些类型的智能指针间的隐式转换,需要自己实现相应的转换函数。
33、将非尾端类设计为抽象类
只要不是最根本的实体类(不需要进一步被继承的类),都设计成抽象类。
一般做法是将析构函数设计成纯虚函数,注意该纯虚析构函数必须被实现出来。
如果有两个具象类,其中一个要继承另一个,最好设计成一个抽象类,然后两个具象类都继承该类。
34、如何在同一个程序中结合 C++ 和 C
在确保你的C++和C编译器产生兼容的目标文件后,还有四件事需要考虑:
1、名称重整Name Mangling:(C++中,编译器可以将函数名重整,其在底层目标文件中使用了另一个名称);
2、statics(包括static类对象、全局对象、namespace内对象、文件范围内的对象)的初始化:通常要求这些statics要在main之前构造,在main函数之后析构,而main是程序起点,编译器的一个做法是main函数开始处执行构造,在末尾执行析构;
3、动态内存分配:new、delete对应,malloc、free对应;
4、数据结构的兼容性: