1.构造函数与析构函数调用顺序
a.首先调用基类的构造函数(若有基类);若有多个基类,则按基类列出的顺序调用;
b.调用这个类的成员对象的构造函数(若有的话);
d.最后调用这个类自身的构造函数;
c.若有多个成员对象,则按成员对象定义的顺序被调用(与参数列表中列出的顺序无关);
注意:如果有虚基类,则先调用虚基类的构造函,再调用基类的构造函数,如果有多个虚基类,则按虚基类列出顺序调用;析构函数与此相反
总的来说就是:
虚基类列出顺序->基类列出顺序->成员对象定义顺序->自身构造函数 的顺序来调用构造函数
析构函数调用顺序与之相反。
说明:没有默认构造函数的内嵌对象 (不出现在初始化列表中要调用默认构造函数,由于下面的D类已经定义了构造函数,所以无法生成默认构造函数)和引用类型数据成员(因为必须要在初始化时绑定)必须要出现初始化列表中)。
代码如下:
#include <iostream>
#include <cstring>
#include <cassert>
#include <iomanip>
using namespace std;
class A
{
public:
A(){cout<<"A constructor"<<endl;}
A(int xx){
x=xx;
cout<<"A Canshu constructor"<<endl;
}
~A()
{ cout<<"A Deconstruct"<<endl;}
private: int x;
};
class B
{
public:
B()
{cout<<"B constructor"<<endl;}
B(int xx){
x=xx;
cout<<"B Canshu constructor"<<endl;
}
~B(){cout<<"B Deconstruct"<<endl;}
private:int x;
};
class C
{
public:
C()
{cout<<"C constructor"<<endl;}
C(int xx){
x=xx;
cout<<"C Canshu constructor"<<endl;
}
~C()
{ cout<<"C Deconstruct"<<endl;}
private:int x;
};
class D
{
public:
D(int xx)
{cout<<"D constructor"<<endl;}
~D()
{cout<<"D Deconstruct"<<endl;}
private:int x;
};
class Clock
{
public:
Clock(int x1,int x2,int x3,int x4,int x5):a(x1),b(x2),x(x3),p(x4),d(x5)
{
cout<<"Clock constructor"<<endl;
}
Clock(int x4):p(x4),d(x4)
{
cout<<"Clock Default constructor"<<endl;
}
void getX()
{
cout<<x;
}
~Clock()
{
cout<<"Clock Deconstruct"<<endl;
}
private: B b;
private: C c;
private: A a;
private: D d;
private: int x;
private: int &p;
};
int main()
{
int x4=0;
Clock cl(12,34,56,x4,78);
cl.getX();
cout<<endl;
return 0;
}
</pre><pre name="code" class="cpp">
2.拷贝函数调用时机
a.一个对象初始化另一个对象(两种形式:point b(a)或 point c=a)
b.函数调用进行形参和实参结合时(一定是对象传值,传引用不会调用拷贝构造函数)
c.函数的返回值是对象
3.C++传值、引用、指针
a.值传递:将对象的副本通过形参实参结合传递给函数,对形参(对象的副本)操作,不会对原对象产生影响
b.引用传递:引用是原对象的一个别名,没有产生新的副本,对引用操作就是对原对象操作,引用必须初始化,并且不能不能再改变, 定义Point &p=point_a;
c. 指针传递:与引用传递相似,但是不必像引用一样从一而终,其指向可以改变,可以不用初始化,但是会产生指针的副本, 定义Point *p=&point_a;
4.派生三步曲:吸收基类成员、改造基类成员、添加新成员
a.吸收基类成员:将吸收除了构造函数、析构函数之外所有的非静态成员
b.改造基类成员:通过继承方式控制基类成员访问属性,通过同名覆盖改变基类成员功能
c.添加新成员:注意要加入新的构造函数和析构函数(因为这两个函数不能被继承)
d.三种继承特点:不可见的含义是:派生类成员和派生类对象均无法直接访问
5.虚基类、虚函数、纯虚函数、抽象类
a.虚基类是为解决多重继承中共同基类成员重复问题,通过将公共基类设置为虚基类,只会对孙子类成员获得造成影响,即对于来自共同基类的成员只保留共同基类一份拷贝,其他继承关系不变,遵循同名覆盖原则,对于共同基类成员的访问可以通过虚基类及其子类进行作用域运算符进行访问
b.虚函数为解决多重继承中同名覆盖成员访问问题,共同基类的某个函数声明为虚函数,其子类和本身均可以有该函数的具体实现,但是可以通过虚基类的指针在满足类型兼容规则的条件下实现动态绑定,若不声明为虚函数则由类型兼容规则知访问的均为共同基类.
c.纯虚函数侧重提高类的抽象性,在父类中只给出函数声明(类似接口,也可以给出实现,但会同名覆盖,访问方式基类名::函数名( 参数表)),而具体实现由子类完成,声明方式:virtual 函数类型 函数名(参数列表)=0,使用方式与虚函数无异,通过基类指针指向派生类对象实现对派生类成员的访问.
d.抽象类,带有纯虚函数的类即为抽象类,抽象类不能实例化,派生类只有给出了全部纯虚函数的实现时才不是一个抽象类,否则依然是抽象类