一、什么是继承
继承是面向对象三大特性之一,C++中,被继承的类称为基类(父类),继承别的类的类成为派生类(子类),继承除了基类的构造函数和析构函数不继承外,其余成员全部继承。在派生类中继承的成员函数可以重写。通过继承,使得派生类拥有基类的成员。
二、为什么要继承
通过继承,使得派生类拥有基类的成员,这样可以提高代码的可重用性。
三、继承的种类,基本语法是什么
1、按照继承方式可分为公有继承,保护继承,私有继承。
2、按照继承的基类的个数可分为单继承,多继承。
3、按照继承的机制可分为普通继承和虚继承。
基本语法如下:不声明继承方式,默认是私有继承。
class 派生类名:[继承方式] 基类名 { // 派生类成员声明 }
四、继承的特性
1、派生类除了基类的构造函数和析构函数不继承外,其余成员都继承。
2、派生类对基类成员的初始化默认调用的无参构造函数。
3、构造函数和析构函数调用顺序如下表
构造函数和析构函数调用顺序 情况 构造函数 析构函数 只有基类和派生类 基类 ---> 派生类 派生类 ---> 基类 派生类中有内嵌子对象 基类 ---> 内嵌子对象 ---> 派生类 派生类 ---> 内嵌子对象 ---> 基类 在基类中有内嵌子对象 内嵌子对象 ---> 基类 ---> 派生类 派生类 ---> 基类 ---> 内嵌子对象
4、 基类的成员在派生类中的权限属性如下表
基类的成员在派生类中的权限属性 继承方式\成员 public protected private 公有继承 public protected 不可见 保护继承 protected protected 不可见 私有继承 private private 不可见
在继承中,为了不影响成员的隐藏性,又要提供对基类成员的访问效率,可以将基类的成员变量设置为protected。
5、继承中的Shadow(影子)现象。
五、案例
1、构造函数和析构函数调用顺序
(1)只有基类和派生类
#include <iostream> using namespace std; // 基类 class Base { public: Base() { cout << "Base()" << endl; } ~Base() { cout << "~Base()" << endl; } }; // 公有继承 class Test:public Base { public: Test() { cout << "Test()" << endl; } ~Test() { cout << "~Test()" << endl; } }; int main() { Test a; return 0; }
(2)派生类中内嵌子对象
#include <iostream> using namespace std; class A { public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } }; // 基类 class Base { public: Base() { cout << "Base()" << endl; } ~Base() { cout << "~Base()" << endl; } }; // 公有继承 class Test:public Base { A a; // 派生类中内嵌子对象 public: Test() { cout << "Test()" << endl; } ~Test() { cout << "~Test()" << endl; } }; int main() { Test a; return 0; }
(3)基类中内嵌子对象
#include <iostream> using namespace std; class A { public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } }; // 基类 class Base { A a; // 基类中内嵌子对象 public: Base() { cout << "Base()" << endl; } ~Base() { cout << "~Base()" << endl; } }; // 公有继承 class Test:public Base { public: Test() { cout << "Test()" << endl; } ~Test() { cout << "~Test()" << endl; } }; int main() { Test a; return 0; }
(4)多继承中调用顺序跟继承顺序有关
#include <iostream> using namespace std; class A { public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } }; class B { public: B() { cout << "B()" << endl; } ~B() { cout << "~B()" << endl; } }; class C { public: C() { cout << "C()" << endl; } ~C() { cout << "~C()" << endl; } }; // 构造函数初始化顺序是 A, B, C, Test class Test:public A, public B, public C { public: Test() { cout << "Test()" << endl; } ~Test() { cout << "~Test()" << endl; } }; int main() { Test a; return 0; }
2、基类的成员在派生类中的权限属性
(1) 通过公有继承后
#include <iostream> using namespace std; // 基类 class Base { private: int base_private; protected: int base_protected; public: int base_public; Base(int a = 0, int b = 0, int c = 0) { // cout << "Base()" << endl; this->base_private = a; this->base_protected = b; this->base_public =c; } ~Base() { // cout << "~Base()" << endl; } int getPrivate()const { return base_private; } }; // 公有继承 class Test:public Base { public: // 派生类的中基类成员的初始化采用,构造函数参数列表的方式 Test(int a = 0, int b = 0, int c = 0):Base(a, b, c) { // cout << "Test()" << endl; } ~Test() { // cout << "~Test()" << endl; } void show()const { // 基类成员的属性为公有的,公有继承后,保持不变 cout << "public: " << base_public << endl; // 基类成员的属性为保护的,公有继承后,保持不变 cout << "protected: " << base_protected << endl; // 基类成员的属性为私有,公有继承后,在派生类和类外都不可见 // cout << "private: " << base_private << endl; cout << "private: " << getPrivate() << endl; } }; int main() { Test a(1, 10, 100); a.show(); cout << "public: " << a.base_public << endl; // 公有,类外也可以访问 return 0; }
(2) 通过保护继承后
#include <iostream> using namespace std; // 基类 class Base { private: int base_private; protected: int base_protected; public: int base_public; Base(int a = 0, int b = 0, int c = 0) { // cout << "Base()" << endl; this->base_private = a; this->base_protected = b; this->base_public =c; } ~Base() { // cout << "~Base()" << endl; } int getPrivate()const { return base_private; } }; // 保护继承 class Test:protected Base { public: // 派生类的中基类成员的初始化采用,构造函数参数列表的方式 Test(int a = 0, int b = 0, int c = 0):Base(a, b, c) { // cout << "Test()" << endl; } ~Test() { // cout << "~Test()" << endl; } void show()const { // 基类成员的属性为公有的,保护继承后,属性变成保护 cout << "public: " << base_public << endl; // 基类成员的属性为保护的,保护继承后,保持不变 cout << "protected: " << base_protected << endl; // 基类成员的属性为私有,保护继承后,在派生类和类外都不可见 // cout << "private: " << base_private << endl; cout << "private: " << getPrivate() << endl; } }; int main() { Test a(1, 10, 100); a.show(); // cout << "public: " << a.base_public << endl; // 保护,类外不可以访问 return 0; }
(3) 通过私有承后
#include <iostream> using namespace std; // 基类 class Base { private: int base_private; protected: int base_protected; public: int base_public; Base(int a = 0, int b = 0, int c = 0) { // cout << "Base()" << endl; this->base_private = a; this->base_protected = b; this->base_public =c; } ~Base() { // cout << "~Base()" << endl; } int getPrivate()const { return base_private; } }; // 保护继承 class Test:private Base { public: // 派生类的中基类成员的初始化采用,构造函数参数列表的方式 Test(int a = 0, int b = 0, int c = 0):Base(a, b, c) { // cout << "Test()" << endl; } ~Test() { // cout << "~Test()" << endl; } void show()const { // 基类成员的属性为公有的,私有继承后,属性变成私有 cout << "public: " << base_public << endl; // 基类成员的属性为保护的,私有继承后,属性变成私有 cout << "protected: " << base_protected << endl; // 基类成员的属性为私有,私有继承后,在派生类和类外都不可见 // cout << "private: " << base_private << endl; cout << "private: " << getPrivate() << endl; } }; int main() { Test a(1, 10, 100); a.show(); // cout << "public: " << a.base_public << endl; // 私有,类外不可以访问 return 0; }
3、继承中的Shadow(影子)现象
在继承中,当派生类中出现与基类同名成员时,默认指定是派生类中的成员,如果要指定是基类的成员,必须加作用域运算符::,如基类::成员。
在单继承中,出现影子现象可以编译通过;而在多继承中,出现影子现象编译不通过,产生二义性。
#include <iostream> using namespace std; class base { private: int a; public: base(int a = 0) { this->a = a; } void show() { cout << "base::show()" << endl; } }; class Test:public base { public: Test(int a = 0):base(a) { } void show() { cout << "Test::show()" << endl; } }; int main() { Test a(10); a.show(); // 调用Test::show() a.base::show(); // 调用base::show() return 0; }
六、总结
本文讲解继承的知识,包括继承的概念,调用构造函数和析构函数的顺序,基类成员在派生类中的权限属性和继承中的影子现象。其实还有虚继承,放在另外一篇讲,感兴趣的搜索左边的目录栏就可以找到。