首页 > 代码库 > C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类
C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类
类继承
在C++类继承中,一个派生类可以从一个基类派生,也可以从多个基类派生。 从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。
1 //单继承的定义 2 class B:public A 3 { 4 < 派生类新定义成员> 5 }; 6 //多继承的定义 7 class C:public A,private B 8 { 9 < 派生类新定义成员> 10 };
我们这篇主要说单继承。
派生类共有三种C++类继承方式:
公有继承(public)
- 基类的公有成员和保护成员可以作为其派生类的公有成员和保护成员
- 派生类的成员函数可以访问基类中的公有成员和保护成员,无法访问基类中的私有成员
- 派生类的对象可以访问基类的公有成员
私有继承(private)
- 基类的公有成员和保护成员都作为其派生类的私有成员
- 在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承
保护C++类继承(protected)
- 基类的所有公有成员和保护成员都成为派生类的保护成员
- 基类的公有成员和保护成员只能被它的直接派生类成员函数或友元访问
构造函数和析构函数不能被继承
派生类构造函数一般语法如下:
1 派生类名::派生类名(参数总表) 2 :基类名1(参数表1),...,基类名n(参数表n) 3 { 4 初始化语句 5 }
调用父类构造函数:
1 class Parent {2 public:3 Parent(int x, int y);4 };5 6 class SubClass : public Parent {7 public:8 SubClass(int x, int y) : Parent(x, y){}9 };
调用父类函数:
1 class A 2 { 3 public: 4 void show() 5 { 6 std::cout<<"I am class A"<std::endl; 7 } 8 } 9 class B:public A10 {11 public:12 void dosomething()13 {14 A::show();15 }16 }
虚函数
C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。
不定义为虚函数的方法,父类型别的指针指向其子类的实例调用的函数任然是父类的函数。
这个定义放到Java语言中后,可以说Java类中的所有函数都是虚函数。
定义:
1 class Base {2 public:3 virtual void f() { cout << "Base::f" << endl; }4 };
纯虚函数
纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。
定义:
1 virtual <类型><函数名>(<参数表>)=0;
抽象类
C++中并没有abstract这个关键字,一个类是否是抽象类是根据其是否含有纯虚函数来判断的。
抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为受保护的访问控制权限。
抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它就可以创建该类的实例了。
抽象类的规定:
- 抽象类只能用作其他类的基类,不能建立抽象类对象。
- 抽象类不能用作参数类型、函数返回类型或显式转换的类型。
- 可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。
嵌套类
在一个类的内部定义另一个类,我们称之为嵌套类(nested class),或者嵌套类型。之所以引入这样一个嵌套类,往往是因为外围类需要使用嵌套类对象作为底层实现,并且该嵌套类只用于外围类的实现,且同时可以对用户隐藏该底层实现。
虽然嵌套类在外围类内部定义,但它是一个独立的类,基本上与外围类不相关。它的成员不属于外围类,同样,外围类的成员也不属于该嵌套类。嵌套类的出现只是告诉外围类有一个这样的类型成员供外围类使用。并且,外围类对嵌套类成员的访问没有任何特权,嵌套类对外围类成员的访问也同样如此,它们都遵循普通类所具有的标号访问控制。
若不在嵌套类内部定义其成员,则其定义只能写到与外围类相同的作用域中,且要用外围类进行限定,不能把定义写在外围类中。例如,嵌套类的静态成员就是这样的一个例子。
前面说过,之所以使用嵌套类的另一个原因是达到底层实现隐藏的目的。为了实现这种目的,我们需要在另一个头文件中定义该嵌套类,而只在外围类中前向声明这个嵌套类即可。当然,在外围类外面定义这个嵌套类时,应该使用外围类进行限定。使用时,只需要在外围类的实现文件中包含这个头文件即可。
另外,嵌套类可以直接引用外围类的静态成员、类型名和枚举成员,即使这些是private的。
1 #ifndef NESTCLASS_H_ 2 #define NESTCLASS_H_ 3 class A 4 { 5 public: 6 A(); 7 ~A(); 8 void operate(); 9 private:10 class B;11 B* m_b;12 };13 #endif14 #include "nestclass.h"15 #include <iostream>16 using namespace std;17 class A::B18 {19 public:20 B(){}21 ~B(){}22 void operate()23 {24 cout<<"B operate!"<<endl;25 }26 };27 A::A()28 {29 }30 A::~A()31 {32 }33 void A::operate()34 {35 m_b = new B;36 cout<<"A operate!"<<endl;37 m_b->operate();38 }39 #include "nestclass.h"40 void main()41 {42 A a;43 a.operate();44 }
在嵌套类的定义被看到之前我们只能声明嵌套类的指针和引用,如上面在A中定义为B m_b而不是B* m_b将会引发一个编译错误。
C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类