继承
1.三种继承权限
- public公共继承
- protected保护继承
- private私有继承
class Person
{
public:
int m_a;
protected:
int m_b;
private:
int m_c;
};
class Son1 : public Person //公共继承
{
//此时该类继承下来了Person中的所有非静态成员
/*
*公共继承
*父类中的public属性在子类中还是public
*父类中的protected属性在子类中还是protected
*父类中的private属性在子类中还是private
*/
};
class Son2 : protected Person
{
//此时该类继承下来了Person中的所有非静态成员
/*
*保护继承
*父类中的public属性和protected属性在子类中成为了protected属性
*父类中的private属性在子类中成为了private属性
*/
};
class Son3 : private Person
{
//此时该类继承下来了Person中的所有非静态成员
/*
*私有继承
*父类中的public属性和protected属性在子类中成为了private属性
*父类中的private属性在子类中成为了private属性
*/
};
不管哪一种继承方式,子类都不可以访问父类中private属性的成员。
2.继承中构造和析构的顺序
父类先构造,子类再构造;子类先析构,父类再析构
3.继承中的对象模型
- 对于非静态成员变量和函数,按照三种继承权限进行继承(注意继承下来的父类成员的属性变化)
- 对于静态成员变量和函数,也是按照三种继承权限进行继承。但是静态成员不属于父类,继承也不属于子类,虽然子类也可以调用父类中非private的静态成员,但它们不在子类的对象模型中(也不在父类中)。静态变量虽然不属于继承下来的对象模型中,但子类却可以调用;虽然可以调用,但也需要按照父类中的权限来用!
3.因为静态成员不属于任何一个类,属于全局,所以可以将静态成员看作是特殊的静态变量,其他类或者外部可以用,但必须按照相关属性权限来操作
4.继承中同名成员处理方式
- 非静态成员同名:子类对象调用同名成员,默认是调子类中的成员。要想调用父类中的同名,必须加父类作用域。对于同名成员函数,如果子类中有和父类中同名的成员函数,则子类中的这个同名函数回隐藏掉父类中的所有此同名的函数(重载的函数),所以想调用父类中的必须加作用域。
- 静态成员同名:同非静态同名处理方式,子类直接调用,父类加作用域。同时,静态的成员还可以直接通过类名访问。只需要注意一个,通过子类类名访问父类中的同名成员,
son::base::m_a;
class Person
{
public:
void func_a(); //非静态成员函数
static void func_b(); //静态成员函数
int m_a; //非静态成员变量
static int m_b; //静态成员变量
};
class Son : public Person
{
//此时将Person中所有的非静态成员都继承下来,虽然静态成员不属于类,不会在继承的范围内,但在子类中可以使用父类中的静态成员
public:
void func_a();
static void func_b();
int m_a;
static int m_b;
};
//对于同名非静态成员的处理方式
void test1()
{
Son s1;
//如果要使用子类中的同名成员,直接调用即可
s1.m_a = 10;
s1.func_a(); //直接调用的同名成员默认是子类的
//如果要使用父类中的同名成员,需要加父类作用域
s1.Person::m_a = 20;
s1.Person::func_a();
}
//对于同名静态成员的处理方式
void test2()
{
/*
*对于静态成员,调用方式有两种
*1.通过对象调用
*2.通过类名调用
*/
Son s2;
//如果要使用子类中的同名成员,直接调用即可
s2.m_b = 10;
s2.func_b(); //通过对象调用
Son::m_b = 20;
Son::func_b(); //通过类名访问
//如果要使用父类中的同名成员,需要加作用域
s2.Person::m_b = 20;
s2.Person::func_b(); //通过对象访问
Son::Person::m_b = 30;
Son::Person::func_b(); //通过类名访问
}
5.菱形继承
菱形继承:例如羊类继承了动物类,驼类继承了动物类;羊驼类继承了羊类和驼类。
那么菱形继承就出现了一个问题,在羊驼类中,继承下来了两份一模一样的动物类中的成员,当羊驼要使用动物类中的数据时,就会产生二义性(是羊类继承下来的那份还是驼类继承下来的那一份),同时,对于羊和驼继承下来的动物类中的数据,在羊驼类中我们只要一份即可
为了解决这个问题,就需要用到虚继承
解释虚继承:我们不需要两份动物类的成员,只需要一份。那么在羊类继承动物类和驼类继承动物类时做出改变。
class Animal //虚基类
{
public:
int m_age;
};
class Sheep : virtual public Animal //虚继承
{
};
class Tuo : virtual public Animal //虚继承
{
};
class sheeptuo : public Sheep,public Tuo
{
};
//此时就通过虚继承解决了菱形继承的问题
解析虚继承:
当sheep类和tuo类通过虚继承继承animal类时,继承下来的不是animal类中的成员,而是继承了一个vbptr
虚基类指针,在animal中有一个vbtable
虚基类表,sheep和tuo中的vbptr
都指向animal中的vbtable
最后对于虚继承的问题,本人水平不是很高,对此理解的还不是很到位,如果出现问题或者理解出错不够深入的话,希望大佬帮忙指正