继承

来源:互联网 发布:我的淘宝流量暴增 编辑:程序博客网 时间:2024/06/06 01:40
继承的定义形式一般如下:

class 派生类 : 派生方式 基类 {…};    //public, protected, private

派生类生成过程包含3个步骤:
吸收基类的成员
改造基类的成员
添加自己新的成员

继承与派生的概念 由point类 派生出 point3D类#include <iostream>using namespace std;class point//point类定义{private://private成员列表,表示点的坐标信息int xPos;int yPos;public:point(int x = 0, int y = 0)//构造函数,带缺省参数{xPos = x;yPos = y;}virtual void disp()//成员disp函数,用来输出点的信息{cout << "( " << xPos << " , " << yPos << " )" << endl;}int GetX()//读取private成员xPos{return xPos;}int GetY()//读取private成员yPos{return yPos;}};class point3D:public point//3维点类point3D,从point类继承而来{private:int zPos;//在point类基础上增加了zPos坐标信息public:point3D(int x, int y, int z):point(x, y)//派生类构造函数,初始化表中调用基类构造函数{zPos = z;}void disp()//隐藏了基类的中的同名disp函数{cout << "( " << GetX() << " , " << GetY() << " , " << zPos << " )" << endl;}int calcSum()//增添了计算3个数据成员和的函数{return GetX() + GetY() + zPos;}};int main(){point pt1(7, 8);//建立point类对象pt1pt1.disp();//显示pt1的信息point3D pt2(3, 4, 5);//建立point3D类对象pt2pt2.disp();//显示pt2的信息int res = pt2.calcSum();//计算pt2中3个坐标信息的加和cout << res << endl;//输出结果return 0;}

不论何种继承方式,下面这些基类的特征是不能从基类继承下来的:
构造函数
析构函数
用户重载的new 、delete运算符
operator new /operator delete 
用户重载的=运算符
友元关系(单向性,不具备传递性)



通过继承,派生类自动得到了除基类私有成员以外的其它所有数据成员和成员函数,在派生类中可以直接访问。
private成员是私有成员,只能被本类的成员函数所访问,派生类和类外都不能访问。
public成员是公有成员,在本类、派生类和外部都可访问
protected成员是保护成员,只能在本类和派生类中访问。是一种区分血缘关系内外有别的成员。
派生类的访问权限规则如下:
1.不管是什么继承方式,子类中都不能访问父类的私有成员。
2.子类内部除了父类的私有成员不可以访问外,其他的都可以访问。
3.除了公有继承基类中的公有成员,子类对象可以访问外,其他的,子类对象一律不能访问 。

private比较简单就不说了,说说protected,Let's code

#include <iostream>using std::cout;using std::endl;class Point{public:Point(int ix = 0, int iy = 0): _ix(ix), _iy(iy){}int getX() const{return _ix;}int getY() const  //如果派生类采用protected继承,则基类public成员在派生类内部具有protected权限{return _iy;}void display() const{cout << "(" << _ix << "," << _iy << ")" << endl;}private://私有成员只能本类内部进行访问int _ix;protected://保护成员只对派生类进行开放int _iy;//在派生类Point3D内是具有protected权限};class Point3D : protected Point{public:Point3D(int ix, int iy, int iz): Point(ix, iy), _iz(iz){}void print() const{//cout << "(" << _ix//基类私有成员不能在派生类内部直接进行访问cout << "(" << getX()//基类私有成员不能在派生类内部直接进行访问 << "," << _iy//基类保护成员可以在派生类内部直接进行访问 << "," << _iz << ")" << endl;}private:int _iz;};class Point4D: public Point3D// _iy在Point4D内部仍然是具有protected权限{private:int _iq;};int main(void){Point3D pt1(3, 4, 5);pt1.display();pt1.getX();//对于派生类对象而言,派生类protected继承自基类时,基类所有成员都不能直接访问pt1.getY();//pt1._iy;//Errorreturn 0;}

多基派生的二义性问题以及解决:

#include <iostream>using std::cout;using std::endl;class A{public:void print(){cout << "A::print()" << endl;}};class B{public:void print(){cout << "B::print()" << endl;}};//多重继承时,发生的是命名冲突,可以采用作用域限定符解决class C : public A, public B{public:void show(){A::print();B::print();}};int main(void){C c;c.show();c.B::print();}

共同基类二义性问题的解决方案

使用关键字virtual将共同基类A声明为虚基类,可有效解决上述问题。

#include <iostream>using std::cout;using std::endl;//菱形继承时如果出现二义性,叫做存储二义性class A{public:A(int ix = 0) : _ix(ix){}void setX(int ix){_ix = ix;}void display(){cout << "A::_ix = " << _ix << endl;}private:int _ix;};class B : virtual public A{};class C : virtual public A{};class D : public B, public C{public:D(int ix): A(ix){}};int main(void){D d(3);d.B::display();d.C::display();d.A::display();//即使使用作用域限定符也不能解决return 0;}

尽管看起来很相似,但虚基派生和多基派生带来的二义性有些细微的差别:
多基派生的二义性主要是成员名的二义性,通过加作用域限定符来解决。
虚基派生的二义性则是共同基类成员的多重拷贝带来的存储二义性,使用virtual派生来解决。

另外,二义性的检查是在访问权限检查之前进行的,
因此,成员的访问权限是不能消除二义性的 

派生时,构造函数和析构函数是不能继承的,为了对基类成员进行初始化,必须对派生类重新定义构造函数和析构函数,并在构造函数的初始化列表中调用基类的构造函数。
由于派生类对象通过继承而包含了基类数据成员,因此,创建派生类对象时,系统首先通过派生类的构造函数来调用基类的构造函数,完成基类成员的初始化,而后对派生类中新增的成员进行初始化。
1、如果派生类有显式定义构造函数,而基类没有,则创建派生类的对象时,派生类相应的构造函数会被自动调用,此时都自动调用了基类缺省的无参构造函数。

#include <iostream>using std::cout;using std::endl;//1. 基类没有显式定义构造函数,但派生类有显式定义构造函数//   创建派生类对象时,会自动调用基类的无参构造函数class Base{public:Base(){cout << "Base()" << endl;}};class Derived : public Base{public:Derived(){cout << "Derived()" << endl;}Derived(int ix){cout << "Derived(int)" << endl;}};int main(void){Derived d1;Derived d2(1);return 0;}

执行结果为:

Base()Derived()Base()Derived(int)
2、如果派生类没有显式定义构造函数而基类有,则基类必须拥有默认构造函数

#include <iostream>using std::cout;using std::endl;//2. 基类有显式定义构造函数,但派生类没有显式定义构造函数//   创建派生类对象时,会自动调用基类的无参构造函数,此时//   在基类内部必须显式定义无参构造函数class Base{public:#if 1Base(){cout << "Base()" << endl;}#endifBase(int ix){cout << "ix = " << ix << endl;}};class Derived : public Base{public:};int main(void){Derived d1;return 0;}

执行结果为

Base()

3、如果派生类有构造函数,基类有默认构造函数,则创建派生类的对象时,基类的默认构造函数会自动调用,如果你想调用基类的有参构造函数,必须要在派生类构造函数的初始化列表中显示调用基类的有参构造函数。

#include <iostream>using std::cout;using std::endl;//3. 基类有显式定义构造函数,但派生类有显式定义构造函数////   创建派生类对象时,如果希望调用的是基类的有参构造函数,//   则必须要在派生类构造函数的初始化列表之中显式调用基类//   的有参构造函数class Base{public:Base(): _ix(0){cout << "Base()" << endl;}Base(int ix): _ix(ix){cout << "Base(int)" << endl;}~Base(){cout << "~Base()" << endl;}void display()const{cout << "Base::_ix = " << _ix << endl;}private:int _ix;};class Derived : public Base{public:Derived(): Base(){cout << "Derived()" << endl;}Derived(int ix): Base(ix) //显式调用基类构造函数{cout << "Derived(int)" << endl;}~Derived(){cout << "~Derived()" << endl;}};int main(void){Derived d1;d1.display();Derived d2(1);d2.display();return 0;}

执行结果为:

Base()Derived()Base::_ix = 0Base(int)Derived(int)Base::_ix = 1~Derived()~Base()~Derived()~Base()

4.如果派生类和基类都有构造函数,但基类没有默认的无参构造函数,即基类的构造函数均带有参数,则派生类的每一个构造函数必须在其初始化列表中显示的去调用基类的某个带参的构造函数。如果派生类的初始化列表中没有显示调用则会出错,因为基类中没有默认的构造函数。如

#include <iostream>using std::cout;using std::endl;//4. 基类有显式定义构造函数,但没有显式定义无参构造函数;// 派生类有显式定义构造函数,则创建派生类对象时,//   则必须要在派生类构造函数的初始化列表之中显式调用基类//   的有参构造函数class Base{public:Base(int ix): _ix(ix){cout << "Base(int)" << endl;}void display()const{cout << "Base::_ix = " << _ix << endl;}private:int _ix;};class Derived : public Base{public:Derived(): Base(0){cout << "Derived()" << endl;}Derived(int ix): Base(ix) //显式调用基类构造函数{cout << "Derived(int)" << endl;}};int main(void){Derived d1;d1.display();Derived d2(1);d2.display();return 0;}

执行结果为:

Base(int)Derived()Base::_ix = 0Base(int)Derived(int)Base::_ix = 1


1 0