本文最后更新于:1 年前
(一)概念:
继承机制是面向对象程序设计中最重要的一个概念,也是使代码可以复用的最重要的手段。
继承机制允许我们依据一个类来定义另一个类,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,能使对类的创建和维护更加容易——能够重用代码功能和提高执行效率。
被继承的类,也就是已有的类,被称为基类(父类),而发生继承的类,也就是新建的类,被称为派生类(子类)。
如果要使用基类的成员,派生类不需要重新编写新的数据成员和成员函数,只需要指定继承的已有的类的成员。但是,派生类不能继承基类的构造函数、析构函数、拷贝构造函数、重载运算符和友元函数。
一个基类可以派生出多个派生类,一个派生类也可以从多个基类中继承数据成员和成员函数。
派生类只能访问基类的非私有成员。
(二)继承的语法形式:
class 派生类名:基类名表
{
数据成员和成员函数声明
};
其中,基类和一般情况下声明的类基本相同。
基类名表的组成为:
访问控制 基类名1 , 访问控制 基类名2 , .......
访问控制是关键字,表示派生类对基类的继承方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| using namespace std; class person { }; class animal { }; class knowledge{}; class student :public animal,protected person,private knowledge { }; class teacher:public animal, protected person, private knowledge { };
|
(三)继承的三种方式:
访问控制的关键字共有三个,分别为public、private和protected。
如果未直接指定访问控制关键字,默认为private。
访问控制决定了不同的访问权限和访问类型,详细情况见下表。
可以看到,对于基类成员,派生类的继承如下:
- 基类的私有成员,派生类不可以访问
- 基类的保护成员,派生类可以继承为自己的保护成员(protected继承)和私有成员(private继承),在派生类可以访问,在外部不可以访问。
- 基类的公有成员,子类可以继承为自己的公有成员(public继承),保护成员(protected继承)和私有成员(private继承)。在派生类可以访问,在外部也可以访问。
对于派生类,公有继承保持基类的保护成员和公有成员不变;保护继承将基类的公有和保护成员变为保护成员;私有继承则将公有和保护成员变为私有成员。
注意:通过派生类可以初始化基类的私有数据成员,方式是通过调用基类的构造函数来实现对私有数据成员的初始化。
注意:虽然基类的私有数据成员不能在派生类中直接访问,但是派生类的对象也会为其建立私有的数据空间,所有继承时即使基类数据成员均为私有,也会导致派生类的占用空间很大。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #include<iostream> using namespace std; class Axy { private: string Aname; protected: double x; double y; public: Axy(double d1 = 0, double d2 = 0,string s = "pointA" ):Aname(s),x(d1),y(d2){ } double getx() { return x; } double gety() { return y; } string getAname() { return Aname; } }; class Bxy :public Axy { private: string Bname; public: Bxy(double d1 = 0, double d2 = 0, string s1 = "pointB",string s2 ="pointA") :Bname(s1), Axy(d1, d2, s2) {} }; class Cxy:protected Axy { private: string Cname; public: Cxy(double d1 = 0, double d2 = 0, string s1 = "pointC") :Cname(s1) { x = d1; y = d2; } void use_A_function() { cout << getx() << endl; cout << gety() << endl; return; } void use_A_function2() { cout << x << endl; cout << y << endl; return; } }; class Dxy:private Cxy { private: string Dname; public: Dxy(double d1 = 0, double d2 = 0, string s = "pointD") :Dname(s), Cxy(d1, d2) {} }; class Exy :public Dxy { private: string Dname; public: Exy(double d1 = 0, double d2 = 0, string s = "pointD") :Dname(s), Dxy(d1, d2) {} }; int main() { Bxy b(1,1,"bbb","aaa"); cout << "b:" << b.getx() << "," << b.gety() << endl; cout << "Aname:" << b.getAname() << endl; Cxy c; c.use_A_function(); c.use_A_function2(); Dxy d; Exy e; cout << sizeof(Axy) << endl; cout << sizeof(Bxy) << endl; cout << sizeof(Cxy) << endl; cout << sizeof(Dxy) << endl; cout << sizeof(Exy) << endl; return 0; }
|
(四)重名成员:
-
同名也称为隐藏,派生类定义了与基类同名的成员时,派生类的同名成员会屏蔽掉基类的同名成员——子类优先。
-
如果要使用基类的同名成员,需要显式地使用类名限定符。
-
对于成员函数,同名的要求是函数名相同,对参数列表没有要求。
-
注意基类和派生类的作用域是独立的(表现为各有自己的this指针),但是基类的作用域被延伸到了派生类中(也就是在派生类的作用域中可以调用基类的作用域)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include<iostream> using namespace std; class Axy { private: string Aname; protected: double x; double y; public: Axy(double d1 = 0, double d2 = 0,string s = "pointA" ):Aname(s),x(d1),y(d2){ } double getx() { return x; } double gety() { return y; } string getAname() { return Aname; } }; class Bxy :public Axy { private: string Bname; protected: double x; double y; public: Bxy(double d1 = 0, double d2 = 0, double d3=0,double d4=0,string s1 = "pointB",string s2 ="pointA"):x(d1),y(d2),Bname(s1), Axy(d3, d4, s2) {} double getx() { return x; } double gety() { return y; } double getAx() { return Axy::x; } double getAy() { return Axy::y; } string getAname() { return Axy::getAname(); } string getBname() { return Bname; } };
int main() { Bxy b; cout << "b:" << b.getx() << "," << b.gety() << endl; cout << "a:" << b.getAx() << "," << b.getAy() << endl; cout << "a:" << b.Axy::getx() << "," << b.Axy::gety() << endl; cout << "bname:" << b.getBname() << endl; cout << "aname:" << b.getAname() << endl; cout << "aname:" << b.Axy::getAname() << endl; return 0; }
|
(五)派生类访问静态成员:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include<iostream> using namespace std; class A { public: static int i; static void add_i() { i++; return; } void print() { cout << "i:" << i << endl; } }; int A::i = 0; class B:protected A { public: void add_i2() { i++; return; } };
int main() { A a; B b; a.i++; a.add_i(); b.add_i2(); A::i++; A::add_i(); a.print(); return 0; }
|