1.继承的本质是什么?
answer:继承的本质其实就是代码复用,派生类复用基类的代码。
2.派生类从基类继承来的成员的访问限定?
3.private和protected的区别?
private:声明的方法和属性,只能被定义方法和属性的类访问。
protected:声明的方法和属性只能被类本身和其继承的子类来进行访问。
4.派生类怎么初始化从基类继承来的成员?
answer:必须调用基类的构造函数来对继承来的成员来进行初始化。
5.重载、隐藏和覆盖
1、重载的条件:
answer:函数名相同,作用域相同 参数列表不同的函数之间。
2、隐藏的条件:
answer:基类和派生类之中,函数名相同的函数
class A
{
public:
void show()
{
cout << "A.show()" << endl;
}
};
class B :public A
{
public:
void show()
{
cout << "B.show()" << endl;
}
};
int main()
{
B b;
b.show();
b.A::show();
return 0;
}
程序打印结果为:
B.show()
A.show()
原因是,在派生类中重新声明了一个show()函数,从基类继承来的show()函数会被隐藏掉。要想访问从基类继承的show()函数,必须加上基类的作用域,这样就可以进行访问了。
3.覆盖的条件
answer:基类和派生类之中,函数的返回值,函数名,参数列表都相同,而且基类的函数是虚函数。
6、基类和派生类的相互赋值
class Base
{
public:
Base(int a) :ma(a) { cout << "Base()" << endl; }
~Base() { cout << "~Base()" << endl; }
virtual void show() { cout << "Base::show()" << endl; }
virtual void show(int i) { cout << "Base::show(int)" << endl; }
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data) :Base(data), mb(data) { cout << "Derive()" << endl; }
~Derive() { cout << "~Derive()" << endl; }
virtual void show() { cout << "Derive::show()" << endl; }
private:
int mb;
};
int main()
{
Derive d(20);
Base *pb = &d;
pb->show(); //静态绑定 Base::show call Base::show (0E912DAh)
/*
动态绑定 vfptr vftable什么时候生成,运行时加载到哪块内存
mov eax, dword ptr[pb]
mov ecx, dword ptr[eax]
call ecx
*/
cout << sizeof(Base) << endl; // 4 8
cout << sizeof(Derive) << endl; // 8 12
// 识别的都是静态(编译时期)类型,显示识别的是RTTI run-time type infomation
cout << typeid(pb).name() << endl; // (静态 去掉基类和派生类的vurtual)Base* (动态)Base*
cout << typeid(*pb).name() << endl; // (静态 去掉基类和派生类的vurtual)Base (动态)Derive
return 0;
}
7、请解释静态(编译)绑定和动态(运行)绑定
如果一个类包含有虚函数,在类型在编译时期会产生一个对应的虚函数表,存虚函数得地址。运行得时候放在.rodata段。实例化对象得时候会产生一个指针,用于指向虚函数表得地址。一个类中定义一个虚函数和定义十个虚函数,只影响虚函数表的大小,不影响对象的大小。继承来的虚函数,编译的时候也会产生虚函数表。
继承的时候 ,如果派生类之中里面有和基类函数名相同 ,参数列表相同的函数 ,如果基类中的此函数为虚函数,编译器会自动把派生类中的这部分代码处理为虚函数,且将地址存入虚函数表中,将虚函数表的地址作为派生类的一个成员属性。
8、怎么理解多态?
静态的多态:编译时期 函数重载和模板。
动态的多态:继承 虚函数。
9、RTTI运行时的信息类型。
RTTI指针存储在虚函数表vftable当中,指向一段类型字符串。
10、抽象类和纯虚函数
1、基类一般不代表任何实体,定义一些派生类共有的属性,一般不进行实例化。
2、virtual void bark () = 0;称为纯虚函数,拥有纯虚函数的类称为抽象类 ,纯虚函数必须在派生类中进行定义,否则派生类将没有意义,不能进行实例化。
3、抽象类和普通类最大的区别是:抽象类不能进行实例化,但是可以定义指针和引用。
11、继承中的几点问题?
1.析构函数能不能实现成虚析构函数?
answer:可以。将析构函数声明为虚析构函数,当基类指针指向派生类对象的时候,这时候通过基类指针来释放派生类对象,虚析构函数就显得特别有用。
2.在构造/析构函数中调用虚函数,是静态绑定还是动态绑定?
answer:构造函数中是不会发生动态绑定的,因为虚函数是依赖对象的,在构造函数中国对象还没有进行实例化。
在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。
3、静态成员函数是和类进行对应的,因此是不能进行动态绑定的。内联函数以前不能进行动态绑定,现在可以。
4、什么时候析构函数必须写成虚析构函数?
answer:当基类指针或引用指向堆上创建的派生类对象的时候。
5、用对象调用虚函数永远是静态绑定,动态绑定首先要用指针或者引用来调用虚函数。
12、多重继承
1、多重继承的坏处?
answer:在菱形继承中,最下面的派生类会有两份间接基类的成员属性。
2、怎么解决?
answer:虚基类(虚继承),会产生虚基类指针,相当于虚函数表的虚函数表的指针。
3、虚基类是什么?
answer:http://www.cnblogs.com/yiranlaobaitu/p/3764422.html