面向对象之C++中的继承

本文详细介绍了C++中的继承概念及其实现方式,包括单继承、多继承和菱形继承,并探讨了不同继承类型的特点和使用场景。此外,还讨论了继承中的构造函数和析构函数的调用顺序、继承的二义性及其解决方案——虚基类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.何为继承

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
在C++中,所谓“继承”就是在一个已存在的类的基础上建立一个新的类。已存在的类称为“基类(base class)”或“父类(father class)”。新建立的类称为“派生类(derived class)”或“子类(son class)”。

2.继承的种类

单继承(single inheritance):一个派生类只从一个基类派生。
多继承(multiple inheritance):允许一个派生类同时继承多个基类。
菱形继承(diamond inheritance):两个子类继承同一个父类,而又有子类同时继承这两个子类。又称钻石继承。

3.继承定义格式

这里写图片描述

继承关系&访问限定符:

这里写图片描述

这里写图片描述

4.继承方式

1-> 共用继承
在定义一个派生类的时候将继承方式指定为public时,称为公用继承。
eg:访问共有基类的成员。
define _CRT_SECURE_NO_WARNINGS 1

include <iostream>

using namespace std;

class Student
{
public:
void get_value()
{
cin >> num >> name >> sex;
}
void display()
{
cout << “num:” << num << endl;
cout << “name:” << name << endl;
cout << “sex:” << sex << endl;
}

private:
int num;
char name;
char sex;
};

class Student1 :public Student
{
public:
void display_1()
{
cout << “num:” << num << endl;
cout << “name:” << name << endl;
cout << “sex:” << sex << endl;
cout << “age:” << age << endl;
cout << “addr:” << addr << endl;
}

private:
int age;
char addr;
};

int main()
{
Student1 stud;
stud.display();
stud.display_1();
return 0;
}
这里写图片描述
派生类无法访问基类中的私有成员。
2-> 私有继承
在声明派生类的时候将基类的继承方式指定为private的。
class Student1 :private Student
{
public:
void display_1()
{
//cout << “num:” << num << endl;
//cout << “name:” << name << endl;
//cout << “sex:” << sex << endl;
cout << “age:” << age << endl;
cout << “addr:” << addr << endl;
}

private:
int age;
char addr;
};

int main()
{
Student1 stud;
//stud.display();
stud.display_1();
stud.age = 18;
return 0;
}

这里写图片描述
所以可以看到:
(1)不能通过派生类对象引用从私有基类继承过来的任何成员。
(2)派生类的成员函数不能访问私有基类的公用成员。
3-> 保护继承
从类的用户角度来看,保护成员等价于私有成员。但有一点与私有成员不同,保护成员可以被派生类的成员函数引用。

5.派生类函数总结

1-> 构造函数和析构函数
基类的构造函数是不能继承的,在声明派生类时,基类成员的初始化工作也是由派生类的构造函数完成的。
派生类构造函数的任务:
(1)对基类数据成员初始化。
(2)对子对象数据成员初始化。
(3)对派生类数据成员初始化。
在派生时,派生类不能继承基类的析构函数,需要调用派生类的析构函数去调用基类的析构函数。
调用顺序与构造函数刚好相反:先执行派生类自己的析构函数,然后调用子对象的析构函数,最后调用基类的析构函数。

6.继承的二义性

class A{
public:
void f();
}

class B{
public:
void f();
void g();
}

class C:public A,public B{
public:
void g();
void h();
};
如果声明:C c1,则c1.f();具有二义性,而c1.g();无二义性(同名覆盖)。
解决方法:
virtual 修饰说明基类,如:class B1:virtual public B。

—>虚基类:
虚基类主要用来解决多继承时,可能对同一基类继承多次从而产生的二义性。为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝。注意:需要在第一次继承时就要将共同的基类设计为虚基类。虚基类及其派生类构造函数建立对象时所指定的类称为最(远)派生类。
(1)虚基类的成员是由派生类的构造函数通过调用虚基类的构造函数进行初始化的。
(2)在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该虚基类的缺省构造函数。
(3)在建立对象时,只有最派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类的构造函数的调用被忽略。
class B{
public:
int b;
}

class B1:virtual public B{
priavte:
int b1;
}

class B2:virutual public B{
private:
int b2;
}

class C:public B1,public B1{
private:
float d;
}

C obj;
obj.b;//正确的
如果B1和B2不采用虚继续,则编译出错,提示“request for member ‘b’ is ambiguous”。这是因为,不指名virtual的继承,子类将父类的成员都复制到自己的空间中,所以,C中会有两个b。

7.菱形继承总结

这里写图片描述

这里写图片描述

class Person
{
public :
string _name ; // 姓名
};
class Student : public Person
{
protected :
int _num ; //学号
};
class Teacher : public Person
{
protected :
int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
string _majorCourse ; // 主修课程
};
void Test ()
{ // 显示指定访问哪个父类的成员
Assistant a ;
a.Student ::_name = “xxx”;
a.Teacher ::_name = “yyy”;
}

这里写图片描述

这些就是我对C++中继承的认识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值