什么是继承?
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
继承的语法
首先有一个基类
class A
{
public:
int a = 1;
};
子类去继承,语法:class 子类名称 : 继承方式 父类名
class B : public A
{
public:
int b;
};
多继承
class D : public B, public C
{
public:
int d = 4;
};
继承方式分public,protected,private
权限等级公有>保护>私有
公有继承可以继承父类公有和保护成员,且继承下来父类公有还是公有保护还是保护,父类私有不可见。
保护继承可以继承父类公有和保护,且继承下来全变成子类的保护成员,父类私有不可见。
私有继承全都不可见。
继承中的作用域
class A
{
public:
void fun()
{
cout << "A:fun()" << endl;
}
int a = 1;
};
class B : public A
{
public:
void fun(int b)
{
cout << "B:fun()" << endl;
}
int b = 2;
};
B类继承了A类但是fun函数并没有构成函数重载,而是隐藏。在继承体系中基类和派生类都有独立的作用域。子类中有函数和父类同名构成隐藏后,如果想访问父类的函数需要指明作用域。
派生类的成员函数
对于构造函数,子类对象在创建时会先去调用父类的构造函数然后再去调用自己的。先有父类再有子类。
也可以自己显示调用,但必须在初始化列表中调用,否则会发现多调用了一次。
对于析构函数,会先去调用子类的析构再去调用父类的析构函数。因为子类对象析构时可能会用到父类成员,如果先析构父类会有野指针问题。
友元和继承
可以在一个类里面声明谁是他的友元,那么其他类就可以访问这个类的私有保护成员。
继承并不能继承友元关系,基类友元不能访问子类私有和保护成员。
继承与静态成员函数
静态成员函数没有this指针,在所以类成员里面只有一份。无论派生出多少个子类,都只有一个static成员实例。
菱形继承
B,C去继承A。D又同时继承了B,C。导致A的成员在D中有了两份,导致数据沉余。而且你在调用a中成员时编译器就会报错不明确,不知道要调哪一个,数据二义性。
解决方法,虚继承。
class A
{
public:
int a = 1;
};
class B : virtual public A
{
public:
int b = 2;
};
class C : virtual public A
{
public:
int c = 3;
};
class D : public B, public C
{
public:
int d = 4;
};
当使用虚继承后子类中会存一个虚表指针,通过虚表中的偏移量来访问父类中的数据。这样就只需要存一份父类数据就行了,而且通过两虚表找到的都是一个数据没有二义性了。
继承和组合
继承是is-a的关系,耦合度更高,但权限也更大可以访问保护成员。组合是has-a,耦合度低,但是不能访问保护成员。