C++ 继承
1 // 基类 2 class Animal { 3 // eat() 函数 4 // sleep() 函数 5 }; 6 7 8 //派生类 9 class Dog : public Animal { 10 // bark() 函数 11 };
基类 & 派生类
一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下:
class derived-class: access-specifier base-class
其中,访问修饰符 access-specifier 是 public、protected 或 private 其中的一个,base-class 是之前定义过的某个类的名称。如果未使用访问修饰符 access-specifier,则默认为 private。
访问控制和继承
派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。
我们可以根据访问权限总结出不同的访问类型,如下所示:
访问 | public | protected | private |
---|---|---|---|
同一个类 | yes | yes | yes |
派生类 | yes | yes | no |
外部的类 | yes | no | no |
一个派生类继承了所有的基类方法,但下列情况除外:
- 基类的构造函数、析构函数和拷贝构造函数。
- 基类的重载运算符。
- 基类的友元函数。
多继承
多继承即一个子类可以有多个父类,它继承了多个父类的特性。
C++ 类可以从多个类继承成员,语法如下:
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};
其中,访问修饰符继承方式是 public、protected 或 private 其中的一个,用来修饰每个基类,各个基类之间用逗号分隔,如上所示。
菱形继承
多继承(环状继承),A->D, B->D, C->(A,B)
class D{......}; class B: public D{......}; class A: public D{......}; class C: public B, public A{.....};
这个继承会使D创建两个对象,要解决上面问题就要用虚拟继承格式
格式:class 类名: virtual 继承方式 父类名
class D{......}; class B: virtual public D{......}; class A: virtual public D{......}; class C: public B, public A{.....};
虚继承--(在创建对象的时候会创建一个虚表)在创建父类对象的时候
A:virtual public D
B:virtual public D
1 #include <iostream>
2
3 using namespace std;
4 //基类
5
6 class D
7 {
8 public:
9 D(){cout<<"D()"<<endl;}
10 ~D(){cout<<"~D()"<<endl;}
11 protected:
12 int d;
13 };
14
15 class B:virtual public D
16 {
17 public:
18 B(){cout<<"B()"<<endl;}
19 ~B(){cout<<"~B()"<<endl;}
20 protected:
21 int b;
22 };
23
24 class A:virtual public D
25 {
26 public:
27 A(){cout<<"A()"<<endl;}
28 ~A(){cout<<"~A()"<<endl;}
29 protected:
30 int a;
31 };
32
33 class C:public B, public A
34 {
35 public:
36 C(){cout<<"C()"<<endl;}
37 ~C(){cout<<"~C()"<<endl;}
38 protected:
39 int c;
40 };
41
42 int main()
43 {
44 cout << "Hello World!" << endl;
45 C c; //D, B, A ,C
46 cout<<sizeof(c)<<endl;
47 return 0;
48 }
结果
Hello World! D() B() A() C() 40 ~C() ~A() ~B() ~D()
为什么子类的构造函数中会出现在初始化列表中呢?原因在于子类能够从基类继承的内容限制上。
我们知道,一个派生类继承了所有的基类方法,但下列情况除外:
- 基类的构造函数、析构函数和拷贝构造函数。
- 基类的重载运算符。
- 基类的友元函数。
因此,我们不能够在子类的成员函数体中调用基类的构造函数来为成员变量进行初始化。例如这样子是不可以的
1 #include <iostream> 2 3 using namespace std; 4 5 // 基类 6 class Shape 7 { 8 public: 9 Shape(int w,int h) 10 { 11 width=w; 12 height=h; 13 } 14 protected: 15 int width; 16 int height; 17 }; 18 19 // 派生类 20 class Rectangle: public Shape 21 { 22 public: 23 Rectangle(int a,int b) 24 { 25 Shape(a,b); //错误的 26 } 27 28 29 };
但我们可以把基类的构造函数放在子类构造函数的初始化列表上,以此实现调用基类的构造函数来为子类从基类继承的成员变量初始化。
1 #include <iostream>
2 using namespace std;
3 // 基类
4 class Shape
5 {
6 public:
7 Shape(int w,int h)
8 {
9 width=w;
10 height=h;
11 }
12 protected:
13 int width;
14 int height;
15 };
16 // 派生类
17 class Rectangle: public Shape
18 {
19 public:
20 Rectangle(int a,int b):Shape(a,b)
21 {
22 }
23 };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?