5.C++子类继承父类后子类的大小
#include <iostream>
using namespace std;
class A
{
private:
int a;
};
class B:public A
{
private:
int b;
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
return 0;
}
刚开始我一想子类继承父类不会继承父类的私有变量,如此我认为结果为4,4(错误)。而事实上结果是4,8。也就是说子类把父类的私有变量也继承下来了,但是却无法访问,对于我这种菜鸟来说一下子没法转个弯来,后来看看资料焕然大悟,子类虽然无法直接访问父类的私有变量,但是子类继承的父类的函数却可以访问,不然的话如果只继承函数而不继承变量,哪么父类的函数岂不成了无米之炊了。所以必须把父类的所有变量都继承下来,这样既能保护父类的变量也能使用父类的函数。
4.多继承的构造顺序
构造对象的规则需要扩展以控制多重继承。构造函数按下列顺序被调用:
- 任何虚拟基类的构造函数按照它们被继承的顺序构造;
- 任何非虚拟基类的构造函数按照它们被继承的顺序构造;
- 任何成员对象的构造函数按照它们声明的顺序调用;
- 类自己的构造函数。
一个有意思的问题:为什么析构函数要设置成虚函数
Range *r1 = new Circle(3, 4);
如果析构函数不是虚函数,则r1在释放内存时,则调用提Range的析构函数。
结果并不是想要的结果,我们想要的结果是调到Circle对象的析构函数。
如果析构函数是虚函数,有多态的支持,r1调用Circle对象的析构函数,Circle对象的析构函数默认调用父类Range的析构函数,保证Circle和Range对象的内容都得到清除。
4.c++重载、覆盖、隐藏的区别和执行方式
既然说到了继承的问题,那么不妨讨论一下经常提到的重载,覆盖和隐藏
4.1成员函数被重载的特征
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
4.2“覆盖”是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
4.3“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,特征是:
(1)如果派生类的函数与基类的函数同名,但是参数不同,此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,但是参数相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
小结:说白了就是如果派生类和基类的函数名和参数都相同,属于覆盖,这是可以理解的吧,完全一样当然要覆盖了;如果只是函数名相同,参数并不相同,则属于隐藏。
重载:函数名相同,函数的参数个数、参数类型或参数顺序三者中必须至少有一种不同。函数返回值的类型可以相同,也可以不相同。发生在一个类内部。
重定义:也叫做隐藏,子类重新定义父类中有相同名称的非虚函数 ( 参数列表可以不同 ) ,指派生类的函数屏蔽了与其同名的基类函数。可以理解成发生在继承中的重载。
重写:也叫做覆盖,一般发生在子类和父类继承关系之间。子类重新定义父类中有相同名称和参数的虚函数。(override)
令人迷惑的隐藏规则
本来仅仅区别重载与重写并不算困难,但是C++的隐藏规则(遮蔽现象)使问题复杂性陡然增加。这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏。
这种隐藏规则,不仅仅是表现在对成员函数上,对同名的data member也是如此。
4.4 三种情况怎么执行:
4.4.1 重载:看参数。
4.4.2 隐藏:用什么就调用什么。
4.4.3 覆盖:调用派生类。