C++面向对象---NO2.继承

继承

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 Son3private Person
{
	//此时该类继承下来了Person中的所有非静态成员
	/*
	*私有继承
	*父类中的public属性和protected属性在子类中成为了private属性
	*父类中的private属性在子类中成为了private属性
	*/
};

不管哪一种继承方式,子类都不可以访问父类中private属性的成员。

2.继承中构造和析构的顺序

父类先构造,子类再构造;子类先析构,父类再析构

3.继承中的对象模型

  1. 对于非静态成员变量和函数,按照三种继承权限进行继承(注意继承下来的父类成员的属性变化)
  2. 对于静态成员变量和函数,也是按照三种继承权限进行继承。但是静态成员不属于父类,继承也不属于子类,虽然子类也可以调用父类中非private的静态成员,但它们不在子类的对象模型中(也不在父类中)。静态变量虽然不属于继承下来的对象模型中,但子类却可以调用;虽然可以调用,但也需要按照父类中的权限来用!
    3.因为静态成员不属于任何一个类,属于全局,所以可以将静态成员看作是特殊的静态变量,其他类或者外部可以用,但必须按照相关属性权限来操作

4.继承中同名成员处理方式

  1. 非静态成员同名:子类对象调用同名成员,默认是调子类中的成员。要想调用父类中的同名,必须加父类作用域。对于同名成员函数,如果子类中有和父类中同名的成员函数,则子类中的这个同名函数回隐藏掉父类中的所有此同名的函数(重载的函数),所以想调用父类中的必须加作用域。
  2. 静态成员同名:同非静态同名处理方式,子类直接调用,父类加作用域。同时,静态的成员还可以直接通过类名访问。只需要注意一个,通过子类类名访问父类中的同名成员,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

最后对于虚继承的问题,本人水平不是很高,对此理解的还不是很到位,如果出现问题或者理解出错不够深入的话,希望大佬帮忙指正

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值