构造与析构:

  说道底还是编译器帮我们在多做了一些工作,生成了一些额外代码。

  需要注意的是:

1: void Test( Father oP )
2: {
3: }
4:
5: int main()
6: {
7:     Father oA;
8:     Test(oA);
9:     return 0;
10: }

  会调用拷贝构造函数。

  重载:

  一样还是编译器的功劳,C++后生成的函数名是与参数有关的,所以又不同参数的函数后生成的函数名不同,看似同名,实则不同。在函数调用的时候,编译器会判断参数的类型,相应的可以生成一个函数名进行“匹配”。( 当然不止这么简单,还会考虑发生类型转换的情况 )

  继承:

  从内存布局的角度上看

1: struct Child : Father

  和

1: struct Child
2: {
3:     Father o;
4:     //other
5: };

  相同(虚函数情况后面讨论)。子类的前面部分和父类是一样的。

  所以一个接受 Father * 参数的函数可以接受 Child *参数,而且转换是安全的。

  有 Father & 类型参数的函数可以接受 Child &,但是继承方式要public。But , why ?

  protected和private继承模式,子类继承的父类的接口对外都是隐藏的,所以以一个Father &传入的参数所有的方法元素原则上是不可用的,用了肯定是违反规则的,编译器判定这一点,所以报错。

  虚函数:

  比较特别的是这个。

  Question:为什么需要虚函数?

  网上看到的答案:基类可以通过虚函数对子类的相识功能进行管理。(我的C++primer被借走以后此失踪,所以只能网上找了)。

  虚函数具体怎么回事不细说了,讨论一下背后的机制。

  为了能够实现虚函数,每个有虚函数的类有一张对应的虚表。这个虚表储存在只读内存区,记录了对应函数的地址。(PS:一个类只有一个虚表)

  每个类对象都要保存一个虚表指针,保存本类的虚表地址。所以你使用 Father *指针指向一个Child对象,调用的虚函数是Child的。

  虚表指针保存在每个对象的首部。

1: class Child : Father
2: {
3:     int iC_;
4:     void FuncC();
5:     virtual void VF();
6: };