【C++】继承
1. 什么是继承?
2.多重继承
3.继承中的运行顺序
参考:
《c++从入门到精通》 人民邮电出版社
公有继承、私有继承和保护继承 http://blog.sina.com.cn/s/blog_4d7810d801000bbr.html##1
1. 什么是继承?
继承是一种类与类之间的关系,这种关系允许在既有类的基础上创建新类。定义新类时,可以从一个或多个既有类中继承(即复制)所有的数据成员和函数成员,然后加上自己的新成员。
如图所示:动物是基类,哺乳动物是派生类,哺乳动物包含有动物的所有属性,且有自己独特的新属性,这便是继承----哺乳动物类继承了动物类。
继承有三种方式:公有、私有、保护。
1.公有继承(public)
公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的。
2.私有继承(private)
私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
3.保护继承(protected)
保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。
下面列出三种不同的继承方式的基类特性和派生类特性。
不同继承方式的基类和派生类特性
—————————————————————————————————
继承方式 | 基类特性 | 派生类特性
—————————————————————————————————
| public | public
公有继承 | protected | protected
| private | 不可访问
—————————————————————————————————
| public | private
私有继承 | protected | private
| private | 不可访问
—————————————————————————————————
| public | protected
保护继承 | protected | protected
| private | 不可访问
—————————————————————————————————
使用继承的实例:
//继承.cpp #include<iostream> using namespace std; class A { private: int x; public: void setA(int i) { x=i; } void printA() { cout<<x<<endl; } } ; class B:public A // B类公有继承 A类 { private: int y; public: void setB(int i) { y=i; } void printB() { printA(); // 调用基类的成员函数 cout<<y<<endl; } } ; int main() { B b; b.setA(1); // 调用基类的成员函数 b.setB(2); // 调用自己的成员函数 b.printB(); return 0; }
运行结果:
分析:
先是定义了类A,然后定义了类B(公有继承了类A)。之后类B便可以访问类A的公有成员变量和函数。
注意:派生类以继承方式继承了基类,并不说明派生类可以访问基类的private成员。
例如,A类中的x(私有变量),B类不可直接访问,但可以通过访问A类的公有函数setA()来改变x的值。
2.多重继承
一个派生类继承一个基类,为单继承,左图。
一个派生类继承多个基类,为多重继承,右图。
多重继承:class C: public A,public B。但要注意,多重继承有一个问题,易出现二义性。
二义性:
当继承基类时,派生类对象就包含了每一个基类对象的成员。假定以类Z继承了类X和类Y,而类X和类Y又是从相同的基类A派生的,那从类的层次上看,就构成了一个菱形的结构,如下图:
一旦多重继承出现菱形,事情将变得复杂起来。对于基基类的A中的成员,在Z中重叠两次,这不仅增加了存储空间,更严重的是产生了二义性,所以,尽量不要多重继承。
3.继承中的运行顺序
//多重继承.cpp #include<iostream> #include<string.h> using namespace std; class Cpoint { private: int x; int y; public: Cpoint(int i=0,int j=0) :x(i),y(j) //调用构造函数进行初始化 { cout<<"Cpoint构造函数"<<endl; } ~Cpoint() { cout<<"Cpoint 析构函数"<<endl; } } ; class Ctext { private: char text[200]; public: Ctext(char *str) //调用构造函数进行初始化 { strcpy(text,str); cout<<"基类Ctext 构造函数"<<endl; } ~Ctext() { cout<<"基类Ctext 析构函数"<<endl; } } ; class Ccircle { private: Cpoint center; int radius; public: Ccircle(int i,int j,int r) :center(i,j),radius(r) //调用构造函数进行初始化 { cout<<"基类Ccircle 构造函数"<<endl; } ~Ccircle() { cout<<"基类Ccircle 析构函数"<<endl; } } ; class Ccircle_with_text: public Ctext,public Ccircle { private: Cpoint textPosition; public: Ccircle_with_text(int i,int j,int r,char *str) :Ccircle(i,j,r),Ctext(str) //调用构造函数进行初始化 { cout<<"Ccircle_with_text 构造函数"<<endl; } ~Ccircle_with_text() { cout<<"Ccircle_with_text 析构函数"<<endl; } } ; int main() { Ccircle_with_text a(5,5,2,"hello"); return 0; }
运行结果:
分析:
Ccircle_with_text是派生类,Ctext、Ccircle是基类。基类Ccircle和派生类Ccircle_with_text都含有类Cpoint的对象的私有变量,当执行 Ccircle_with_text a(5,5,2,"hello") 创建a对象时:
先调用基类Ctext的构造函数,然后是类Cpoint的构造函数,之后在调用Ccircle的构造函数;
然后在类Ccircle_with_text内部,先调用类Cpoint的构造函数,之后在调用派生类的构造函数;
而析构函数的调用与构造刚好相反。
------------------------------------------- END -------------------------------------