1 继承与派生
前几天讲了类的构造函数和析构函数,今天跟大家学习一下类的继承的知识。
继承是面向对象程序设计中最重要的机制。通过继承机制,可以利用已经有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有自己新定义的成员,而且还同时拥有旧的成员。通常把被继承的类称为基类或父类,继承它的类称为派生类或子类。
下面我们给一个简单的例子,让大家了解一下类的继承如何实现。
1: #include <iostream>2: using namespace std;3:4: //基类 父类
5: class CBase
6: {7: public:
8: CBase()9: {10: mCounter=0;11: }12: ~CBase()13: {14:15: }16: void setCounter(int values)17: {18: mCounter=values;19: }20: int getCounter()
21: {22: return mCounter;
23: }24:25: public:
26: int mCounter;
27: };28: //派生类 子类
29: class CChild:public CBase30: {31:32: };33:34: int main()
35: {36: CChild child;37: //子类继承了父类的函数
38: child.setCounter(123);39: cout<<child.getCounter()<<endl;40: return 0;
41: }42:43:
我们定义了一个父类Cbase,然后定义了它的子类CChild虽然子类里什么也没写,但是它还是继承了父类里的setCounter方法和getCounter方法。
2 常用的继承关系
不知道各位注意没有,子类在继承父类的时候,使用了public关键字,表示公有继承。剩余的继承关系还有私有继承和保护继承。公有继承是最常用的继承方式,而私有继承就比较少用,保护继承就更少用了。下面我们分别来讲解一下这些继承方式。
2.1 公有继承(public)
写继承代码时,在基类前面加上关键字public表示公有继承。公有继承的特点:
- 子类(派生类)的成员函数可以访问基类中的公有成员和保护成员。
- 子类(派生类)的对象可以访问基类中的公有成员。
为了让大家能够清楚地了解公有继承的特点,复制一下下面的代码,亲自试一试吧。
1: #include <iostream>2: using namespace std;3:4: class A
5: {6: public:
7: A()8: {9: mPublic=1;10: mProtected=2;11: mPrivate=3;12: }13: ~A(){}14: void speak()
15: {16:17: }18: int mPublic;
19: private:
20: int mPrivate;
21: protected:
22: int mProtected;
23: };24:25: class B:public A26: {27: public:
28: B(){}29: ~B(){}30: void talk()
31: {32: a=mPublic;33: b=mProtected;34: c=mPrivate;//注意这个位置
35: cout<<a<<" "<<b<<""<<c<<endl;
36: }37: private:
38: int a,b,c;
39: };40:41: int main()
42: {43: B b;44: b.talk();45: int x=b.mPublic;
46: int y=b.mProtected;//注意这个位置47: int z=b.mPrivate;//注意这个位置48: return 0;
49: }50:
编译一下上面的代码,看看你会得到什么答案。不出意外,结果是这样的:
- Error 1 error C2248: 'A::mPrivate' : cannot access private member declared in class 'A' e:\XXX\main.cpp 34
- Error 2 error C2248: 'A::mProtected' : cannot access protected member declared in class 'A' e:\XXX\main.cpp 46
- Error 3 error C2248: 'A::mPrivate' : cannot access private member declared in class 'A' e:\XXX\main.cpp 47
这三个错误还是很好理解的吧,看看公有继承的特点就明白了。派生类B的成员函数talk不能访问基类A的私有变量mPrivate;派生类B只能访问基类A的公有成员mPublic。
2.2 私有继承(private)
写继承代码时,在基类前面加上关键字private表示私有继承。如果子类继承父类时不使用关键字,则默认是私有继承。私有继承的特点:
- 基类的成员只能有直接派生类访问。
- 派生类从基类继承来的成员不能再往下派生。
- 积累的公有成员个保护成员都作为派生类的私有成员。
- 对派生类对象而言,所有基类对象的成员都是不可见的。
2.3 保护继承(protected)
写继承代码时,在基类前面加上关键字protected表示保护继承。保护继承的特点:
- 基类的成员只能由直接派生类访问。
- 派生类从基类继承来的成员不能再往下派生。
- 积累的公有成员个保护成员都作为派生类的保护成员,且不能被派生类的子类访问。
- 对派生类对象而言,所有基类对象的成员都是不可见的。
3 在继承关系中构造函数、析构函数的调用顺序
类对象在初始化时,会先调用父类的构造函数,然后调用自己的构造函数;类对象在析构时,先调用自己的析构函数,再调用父类的析构函数。例如:
1: #include <iostream>2: using namespace std;3:4: class A
5: {6: public:
7: A(){cout<<"This is A constructor."<<endl;}
8: ~A(){cout<<"This is A destructor."<<endl;}
9: };10:11: class B:public A12: {13: public:
14: B(){cout<<"This is B constructor."<<endl;}
15: ~B(){cout<<"This is B destructor."<<endl;}
16: };17:18: class C:public B19: {20: public:
21: C(){cout<<"This is C constructor."<<endl;}
22: ~C(){cout<<"This is C destructor."<<endl;}
23: };24:25: int main()
26: {27: C *p=new C();
28: delete p;
29: p=NULL;30: return 0;
31: }32:
运行结果如下:
4 多继承
C++不同于Java,它支持多继承,即一个派生类有多个基类。基本格式如下:
1: class A
2: {3: public:
4: A(){cout<<"This is A constructor."<<endl;}
5: ~A(){cout<<"This is A destructor."<<endl;}
6: };7:8: class B
9: {10: public:
11: B(){cout<<"This is B constructor."<<endl;}
12: ~B(){cout<<"This is B destructor."<<endl;}
13: };14:15: class C:public A,public B16: {17: public:
18: C(){cout<<"This is C constructor."<<endl;}
19: ~C(){cout<<"This is C destructor."<<endl;}
20: };
看到这,大家可能会产生好奇,如果可以这么定义,那么构造函数和析构函数的调用顺序会是什么样?大家不妨回去自己试一试,可以把这个当作家庭作业哟。这个问题我们会在以后的文章中讲解。
感谢:《C++编程关键路径——程序员求职指南》