继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承的定义格式:
class A
{
public:
int a;
};
class B:public A
{
public:
int b;
};
在以上代码中A类被B类以public的方式所继承,其中A类为基类也称为父类,B类是派生类也称为子类。
继承的方式一共有三种:public、protected、private。
- 以public继承方式继承后的派生类中除了基类中的private成员都可以访问。
- 以protected继承方式继承后的派生类中public成员变为了protected成员,其他没变。
- 以private继承方式继承后的派生类中,public成员和protected成员都变为了private成员。
- 注意基类中的private成员不管什么继承方式都在派生类中不可见。
- 使用class时默认的继承方式是private,使用struct时默认的继承方式是public。
基类和派生类对象的赋值转换
- 派生类对象可以赋值给基类的对象/基类的指针/基类的引用。
- 基类的对象不能赋值给派生类的对象。
- 如果基类是多态的则基类的指针可以通过dynamic_cast强制类型转换赋值给派生类的指针。但是只有当基类指针指向派生类时才是安全的。
- 基类的友元关系不能继承
- 如果基类定义了一个static成员,则整个继承体系里只会存储一个。无论有多少个派生类的子类,都只有一个static成员实例。
隐藏(重定义)
子类和父类中又同名函数时,子类成员将屏蔽父类对同名成员的直接访问。如果是成员函数的隐藏只需要函数名相同就构成隐藏。
单继承与多继承
单继承:一个子类只有一个直接父类
class A
{};
class B:public A
{};
多继承:一个子类有俩个或者俩个以上直接父类
class B
{};
class C
{};
class a :public B,public C
{
};
多态
多态就是不同类的对象,对同一函数调用,采取的多种不同的行为方式。继承就是为多态服务的。
虚函数
virtual修饰的函数
虚函数的重写
如果派生类中有一个跟基类虚函数完全相同的函数,则称为子类重写了基类的虚函数。
class A
{
public:
vitrual void showA()
{
cout << "A" <<endl;
}
};
class B:class A
{
public:
void showA()
{
cout << "B" <<endl;
}
};
int main()
{
A *B;
B.showA();
return 0;
}
其中B类中将A类中的showA函数重写
虚函数重写的俩个例外:
协变(基类与派生类虚函数返回值类型不同)
派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时称为协变。
class A
{};
class B:public A
{};
class C
{
public:
virtual A* f()
{
return new A;
}
};
class D :public C
{
public:
virtual B* f()
{
return new B;
}
};
析构函数的重写
当用一个基类的指针删除一个派生类的对象时,如果没有将基类析构函数声明为虚函数的话派生类的析构函数不会被调用。会造成内存泄漏的情况。
class A
{
public:
A() {};
~A()
{
cout << "A" << endl;
};
};
class B :public A
{
public:
B()
{};
~B()
{
cout << "B" << endl;
}
};
A* b = new B;
delete b;
//输出A
class A
{
public:
A() {};
virtual ~A()
{
cout << "A" << endl;
};
};
class B :public A
{
public:
B()
{};
~B()
{
cout << "B" << endl;
}
};
//输出B A
重载、重写、隐藏
重载:针对函数。函数名相同,参数列表不同。
重写:针对继承。函数名,参数列表,返回值类型完全相同(协变除外),用于虚函数/纯虚函数
隐藏:针对继承。函数名相同,不能时虚函数。
虚函数的实现原理(虚表)
虚表是一个二级函数指针,只要类中包含虚函数,就会在对象的头部包含一个虚表指针(vfptr)。
虚表里存放的是虚函数的地址。
当子类继承父类时,会继承虚表,当子类有新的虚函数时,会在虚表后面新增新的项,当子类重写父类的虚函数时,会把虚表中原有的某一项覆盖。
虚继承:
含有一个虚基类指针(vbptr),指向自己的基类,作用是可以描述自己的父类。当发现被继承的另一个父类中也有这么一个相同的虚基类时,两个基类就会合并,只保留一个。