news 2026/4/28 20:16:48

C++ 继承的范例讲解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 继承的范例讲解

1.继承的概念

继承,是面向对象的三大特性之一。继承可以理解成是类级别的一个复用,它允许我们在原有类的基础上进行扩展,增加新的功能。

当创建一个类时,我们可以继承一个已有类的成员和方法,并且在原有的基础上进行提升,这个被继承的类叫做基类,而这个继承后新建的类叫做派生类。

用法如下:

class [派生类名] : [继承类型] [基类名]

例如:

1

2

3

4

5

6

7

8

9

10

11

classPerson

{

public:

string _name;

int_age;

};

classStudent :publicPerson

{

protected:

string _stuNum;

};

这里的派生类Student就复用了Person的方法和成员,并在此基础上扩展补充。

2.继承方式

继承的方式和类的访问限定符一样,分为public(公有继承),private(私有继承), protected(保护继承)三种。

不同的继承方式,在派生类中继承下来的基类成员的访问权限也不一样。

基类的其他成员在子类的访问方式 = Min(成员在基类的访问限定符,继承方式)

备注:

1.在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能 在派生类的类里面使用,实际中扩展维护性不强。

2.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。

3.基类与派生类的赋值转换

派生类可以赋值给基类的对象、指针或者引用,这样的赋值也叫做对象切割。

例如上面的Person类和Student类

这种赋值只能是派生类赋给基类(但需要割掉多出来的成员例如_ stuID),而基类对象不能赋给派生类。

基类的指针可以强制类型转换赋值给派生类的指针, 如:

1

2

3

4

5

6

7

8

9

10

intmain()

{

Person p1;

Student s1;

Person* hPtr1 = &s1;//指向派生类对象

Person* hPtr2 = &p1;//指向基类对象

Student* pPtr = (Student*)hPtr1;//没问题

Student* pPtr = (Student*)hPtr2;//有时候没有问题,但是会存在越界风险

return0;

}

小结:

1.派生类可以赋值给基类的对象、指针或者引用

2.基类对象不能赋值给派生类对象

3.基类的指针可以通过强制类型转换赋值给派生类的指针。**🍁但是必须是基类的指针是指向派生类对象时才是安全的,否则会存在越界的风险。**这里基类如果是多态类型,可以使用RTT的dynamic_cast来进行识别后进行安全转换。

4.作用域与隐藏

🎄隐藏:隐藏,也叫做重定义,当基类和派生类中出现重名的成员时,派生类就会将基类的同名成员给隐藏起来,然后使用自己的。(但是隐藏并不意味着就无法访问,可以通过指明基类作用域来显式访问隐藏成员。)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

classPerson

{

public:

voidf(intage)

{

cout <<"姓名"<< _name << endl;

cout <<"年龄"<< _age << endl;

}

protected:

string _name;

int_age;

};

classStudent :publicPerson

{

public:

voidf()

{

Person::f(32);//需显式调用f函数

cout <<"学号"<< _stuNum << endl;

}

private:

string _stuNum;

};

例如这里的f( )就构成了隐藏

同时,这里还有个需要注意的问题,在基类与派生类中,同名的方法并不能构成重载,因为处于不同的作用域中。而只要满足方法名相同,就会构成隐藏。

5.派生类的默认成员函数

在每一个类中,都会有6个默认的成员函数,这些函数即使我们自己不去实现,编译器也会帮我们实现。

🎄这里有两点需要注意(笔试题常考):

1.构造函数,拷贝构造,operator=三种情况,都要调用父类对应的构造函数/拷贝构造/operator=进行对父类的成员变量的初始化,并且倘若父类没有默认的构造函数的时候(比如父类写了带参的构造函数),我们就要显式调用(Person(参数…),Person::operator=(参数…))

🍁构造函数显示调用

派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函 数,则必须在派生类构造函数的初始化列表阶段显示调用。

1

2

3

4

5

Student()

:People()

{

cout <<"Student()"<< endl;

}

🍁拷贝构造显示调用

建议拷贝构造都用显示调用,不然免不了出现子类拷贝构造当中调用了父类的构造函数的情况(因为拷贝构造也是构造,在初始化列表处,对于子类而言,父类相当于一个自定义类型对象,子类会调用父类的构造函数对父类的资源进行初始化。)

1

2

3

4

5

Student(constStudent& s)

:People(s)

{

cout <<"Student(const Student& s)"<< endl;

}

🍁派生类的operator=必须要调用基类的operator=完成基类的复制。

1

2

3

4

5

6

7

8

Student& operator=(constStudent& s)

{

cout <<"Student& operator = (const Student& s)"<< endl;

if(this!= &s)

{

Person:: operator=(s);

}

}

🍁析构函数

由于编译器会将析构函数的名字处理成destructor,因此派生类和基类的析构函数会构成隐藏关系,故若要派生类要调用基类的析构函数,那么需要显式调用,但是编译器会默认在派生类的析构函数调用结束后调用基类的析构函数,这样就析构两次了。

1

2

3

4

5

6

7

8

9

~Person()

{

cout <<"~Person()"<< endl;

}

~Student()

{

Person:: ~Person();

cout <<"~Student()"<< endl;

}

在派生类中,基类的析构函数会被隐藏,虽然它们这里的名字不同,但是为了实现多态, 它们都会被编译器重命名为destructor。在调用子类的构造函数时,我们是先调用父类的构造函数,后对子类的成员进行构造。由先构造后析构的顺序,所以我们是在析构函数当中析构子类的资源,析构函数调用完后编译器自动帮我们调用父类的析构函数。

6.友元与静态成员

🍁1.友元

友元关系是不会继承的,如果子类要使用父类的友元,则子类自己也要将其定义为友元。

🍁2.静态成员

基类定义了static静态成员,无论继承了多少次,派生了多少子类,静态成员在这整个继承体系中有且只有一个。静态成员不再单独属于某一个类亦或者是某一个对象,而是属于这一整个继承体系。

7.菱形继承与虚继承

首先简单介绍下单继承、多继承的概念

单继承:一个子类只有一个直接父类时称这个继承关系为单继承

多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承

菱形继承:菱形继承是多继承的一种特殊情况,下面简单举例介绍下菱形继承及其带来的二义性问题:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

classHuman

{

public:

int_age;

};

classStudent :publicHuman

{

public:

int_stuNum;

};

classTeacher :publicHuman

{

public:

int_teaNum;

};

classAssistant :publicTeacher,publicStudent

{

};

哦豁!!!菱形继承这个关系感受到了吧!!!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/28 20:16:44

详解C++的反调试技术与绕过手法

反调试技术的实现方式有很多&#xff0c;最简单的一种实现方式莫过于直接调用Windows系统提供给我们的API函数&#xff0c;这些API函数中有些专门用来检测调试器的&#xff0c;有些则是可被改造为用于探测调试器是否存在的工具&#xff0c;多数情况下&#xff0c;调用系统API函…

作者头像 李华
网站建设 2026/4/28 20:15:22

架构级Dlib预编译方案:企业级Windows环境部署实战指南

架构级Dlib预编译方案&#xff1a;企业级Windows环境部署实战指南 【免费下载链接】Dlib_Windows_Python3.x Dlib compiled binaries (.whl) for Python 3.7-3.14 and Windows x64 项目地址: https://gitcode.com/gh_mirrors/dl/Dlib_Windows_Python3.x 在计算机视觉和机…

作者头像 李华
网站建设 2026/4/28 20:14:21

Labview通讯三菱Q PLC,Labvew TCP通讯三菱PLC ,MCTCP,三菱PLC...

Labview通讯三菱Q PLC&#xff0c;Labvew TCP通讯三菱PLC &#xff0c;MCTCP&#xff0c;三菱PLC连接LabVIEW&#xff0c;LabVIEW和三菱PLC 通讯 三菱官方MC协议&#xff0c;简单方便&#xff0c;完胜OPC协议。 &#xff0c;源码开放。 1.支持bool读写 2.支持浮点数读写 3支持 …

作者头像 李华
网站建设 2026/4/28 20:12:23

分钟搞懂深度学习AI:实操篇:池化层

1. 流图&#xff1a;数据的河流 如果把传统的堆叠面积图想象成一块块整齐堆叠的积木&#xff0c;那么流图就像一条蜿蜒流淌的河流&#xff0c;河道的宽窄变化自然流畅&#xff0c;波峰波谷过渡平滑。 它特别适合展示多个类别数据随时间的变化趋势&#xff0c;尤其是当你想强调整…

作者头像 李华