C++中的继承

继承简介

在这里插入图片描述

    继承就子类继承父类或基类的全部成员函数和成员变量,而且在此基础上继承的子类还可以自己添加自己的成员,如上图所示,子类1,不仅继承了父类的_name和_status_num,而且自身还添加了一个_sex,子类2则多了_is_student,这个与类和对象有点像,只不过这个对象也使类,而且还可以添加自己的成员函数或者成员变量。

继承方式

    继承的具体代码实现如下:

class father//父类/基类
{
    public:
       char* _name;
       int _status_num;
};

//继承
class  son:public father//继承方式 + 继承的类
{
    public:
      char* _sex;//子类自己的成员变量
};

    由上代码可知,子类继承时,就是在自己的类名旁边加上继承方式+父类名,而这个继承方式,就是子类中继承的成员的权限。继承方式的权限问题,看下表所示:

权限父类public父类protected父类provite
子类public继承publicprotected子类中不可见
子类protected继承protectedprotected子类中不可见
子类private继承privateprivate子类中不可见
    由上表可知,成员继承的权限是只能缩小的,权限大小可表示为public > protected > private。其中子类继承时,子类不可见,是因为成员在父类中私有了,子类就看不见了,但是不是没继承。
    值得注意的是,如果没有写继承方式,那么class默认继承方式是private,struct默认继承方式public;如果基类中protected权限的内容,派生类是可以访问的。

基类和派生类对象赋值转换

    派生类对象可以赋值给基类对象,基类指针或基类引用,也可以将其理解为切片,把派生类中基类部分的内容赋值给基类具体可由下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
    我们可以通过下面代码进行测试:

//基类
class Person
{
protected:
	string _name; //姓名
	string _sex;  //性别
	int _age;     //年龄
};
//派生类
class Student : public Person
{
protected:
	int _stuid;   //学号
};
int main()
{
	Student s;
	Person p = s;     //派生类对象赋值给基类对象
	Person* ptr = &s; //派生类对象赋值给基类指针
	Person& ref = s;  //派生类对象赋值给基类引用

	return 0;
}

多继承

在这里插入图片描述

    多继承就是一个子类继承了多个基类的成员,具体代码如下:

class a
{
    int a;
};
class b
{
    int b;
};
class c:public a,public b
{
    int c;
};

继承中的问题

1、基类和子类成员同名会怎样?

    如果基类和子类同名,基类的成员会被隐藏起来,这里不是没继承,如果要使用这个同名的成员,必须指定作用域,不然用不了会报错。

2、基类中的友元函数,子类能继承吗?

    继承不了,比如别人的朋友不一定是你的朋友。

3、继承与静态成员怎么继承?

    若基类中定义了static静态成员变量,则不管继承派生出了多少个子类也只有一个static成员实例,也就是所有的派生类继承的static成员都是同一个,指针指向的都是同一个内存空间。

4、继承中基类和子类,构造析构顺序

    构造:先基类,后子类
    析构:先子类,后基类
    跟栈一样,后入先出。

5、多继承造成的菱形继承问题

在这里插入图片描述
    菱形继承如上图所示,这时D中会有两个a成员,分别来自B和C,然后就会出现数据冗余,而且出现二义性,调用的时候必须指定作用域才能使用。接下来我们看一下测试代码:

#include <iostream>
using namespace std;
class A
{
public:
	int _a;
};
class B : public A
{
public:
	int _b;
};
class C : public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

    我们通过内存窗口可以看到D类对象当中各个成员在内存中的分布情况,如下图:
在这里插入图片描述
    D类对象当中各个成员在内存当中的分布情况如下:
在这里插入图片描述
    可以看出对象D中包含了两个基类成员_a,照成了数据冗余,并且存在二义性,一个_a是派生类B的,一个是C的。如果在继承时加入virtual就可解决数据冗余和二义性问题。具体操作如下代码:

#include <iostream>
using namespace std;
class A
{
public:
	int _a;
};
class B : virtual public A
{
public:
	int _b;
};
class C : virtual public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

    我们通过内存窗口可以看到D类对象当中各个成员在内存中的分布情况,如下图:
在这里插入图片描述
    D类对象当中各个成员在内存当中的分布情况如下:
在这里插入图片描述
    我们可以看出目前对象D中只有一个成员_a,而此时对象D中多了两个指针,而这两个指针是虚基表指针,指向虚基表,虚基表中存放着对象D的指针与成员_a之间的偏移量。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

滋巴糯米团

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值