1、派生类都继承了父类的哪些东西?
派生类继承了基类除构造函数和析构函数外的所有成员。
2、继承方式
派生类继承基类方式 |
基类的的访问限定 |
派生类的访问限定 |
外部访问限定 |
public: |
|
|
|
|
public |
public |
可以访问 |
|
protected |
protected |
不可见 |
|
private |
可继承,不可见 |
不可见 |
protected |
|
|
|
|
public |
protected |
不可见 |
| protected |
protected |
不可见 |
|
private |
可继承不可见 | 不可见 |
private |
|
|
|
|
public |
private |
不可见 |
|
protected |
private |
不可见 |
|
private | 可继承,不可见 |
不可见 |
3、不加继承方式、默认的继承关系是什么?(用class关键字定义的类默认继承方式是private, 而用struct定义的类默认继承方式是public)
class B : A 此时默认继承关系是private继承
struct C : D 此时的默认继承关系是public继承
4、派生类对象的构造与析构
(1)Derive d1:先构造基类部分,再构造派生类,出作用域先析构派生类再析构基类
(2)可以在派生类构造函数的初始化列表中,指定基类部分的构造方式,不指定的话,基类部分就要默认构造。
5、重载:(1)函数名相同(2)参数列表不同。
隐藏:(1)必须出现在继承结构中(2)派生类的作用域把基类的作用域给隐藏了。
覆盖:(1)出现在继承结构中(2)在派生类的虚函数表中,用派生类重写的虚函数把基类继承来的虚函数的地址给覆盖了。
6、动态绑定:指的是运行时候的绑定,通过寻找vfptr,找到vftable,在找到虚函数的地址,进行调用。
#include<iostream>
using namespace std;
class A
{
public:
A(int data) :ma(data)
{
//先把类A的虚函数表地址写到vfptr里面
cout << "A()" << endl;
clear();
}
void clear(){ memset(this, 0, sizeof(*this)); }
virtual void show(){ cout << "A::show ma:" << ma << endl; }
protected:
int ma;
};
class B : public A
{
public:
B(int data) : mb(data), A(data)
{
//先把类B的虚函数表地址写到vfptr里面
cout << "B()" << endl;
}
void show(){ cout << "B::show ma:" << ma << " mb:" << mb << endl; }
private:
int mb;
};
int main()
{
A *p1 = new A(10);
p1->show();//动态绑定
A a(10);
B b(10);
a.show();//静态绑定
b.show();//静态绑定
B * pb=new B(20);
pb->show();//动态绑定
A *p2 = new B(10);//先构造基类部分,再构造派生类部分
p2->show();//动态绑定
return 0;
}
7、什么叫RTTI?
run-time-type-indentify/information运行时候的类型识别
当一个类有虚函数,它编译时会产生一张vftable虚函数表,该虚函数表中放了虚函数的地址,vfptr相对内存的起始位置的偏移量,及RTTI指针(和类型是一一对应的)
8、什么是多态?
动态的多态:基类指针或者引用,指向了从这个基类继承来的不同派生类的对象,通过指针,调用派生类对象和基类的同名覆盖方法,此时,基类指针指向哪个派生类对象,调用的就是哪个派生类对象的方法。(一个指针可以调用多种方法,节省资源)多态其实就是动态绑定的过程。
9、什么时候发生动态绑定?
只要使用指针或者引用,而且调用的函数是虚函数,就一定发生动态绑定。
10、构造函数不可以实现为虚函数,因为虚函数依赖对象,虚函数表的地址存放在对象的前四个字节,若构造函数为虚函数,不构造对象何来的虚函数之谈。析构函数可以实现为虚函数。