类的继承

来源:互联网 发布:江南大学网络教育好吗? 编辑:程序博客网 时间:2024/05/18 16:39

1.继承的特点:基类中所有的成员,都会被子类继承过去。新的派生类中必须有新东西的出现。

2.单继承的特点:父类只有一个。

3.多继承:父类有两个或者多个。

4.三种继承方式:public,private,protected。

   Public继承:父类所有成员在基类中的访问权限不会改变。

   Protected继承:父类成员在基类中都变为protected属性。(private成员例外,不改变访问权限)

   Private继承:父类所有成员在基类都变为private属性。(private成员例外,不改变访问权限)

5.代码如下图:

    #include "Utility.h"

class CFather

{

private:

int m_iMoney;

protected:

int m_iAge;

public:

CFather()

{

cout<<"父类构造函数:"<<endl;

m_iAge = 45;

}

void breath(){cout<<"呼吸!"<<endl;}

};

//继承的特点:基类中所有的成员,都会被子类继承过去

// 父类中的m_iAge,在子类中也会有一个m_iAge

//继承的代码格式:(单继承)

//class 子类名 : 继承方式  父类名

//{

//};

class CSon : public CFather

{

public:

CSon()

{

cout<<"子类构造函数:"<<endl;

m_iAge = 10;

}

void Study()

{

//尝试在子类中使用父类中的私有成员m_iMoney:

//cout<<m_iMoney<<endl;

//尝试在子类中使用父类中的保护成员m_iAge:

cout<<"年龄是"<<m_iAge<<"孩子要上学"<<endl;

}

};

/*

当描述类内部成员访问权限的情况下:

private: 只能在类内访问

protected:本类及子类中

public:随意

当描述类的继承方式时:

*/

void main()

{

//CFather father;

//father.breath();

CSon son;

son.Study();

son.breath();

system("pause");

}

6.父类的第一级子类叫做直接派生类,第二级子类叫做间接派生类。

7.构造派生类对象时,要对其基类数据成员、新增数据成员进行初始化。

<派生类名>::<派生类名>(<参数表>) :

<基类名1>(<参数表1>), ……, <基类名n>(<参数表n>),

 <子对象名1>(<参数表n+1>), ……, <子对象名m>(<参数表n+m>)

{

 <派生类构造函数体>  //派生类新增成员的初始化

}

8.如果父类的构造函数是不带参数的,子类的构造函数则可以不调用。

9.构造函数遵循洋葱结构,先构造的最后析构。

10.先调用基类的构造函数,再调用派生类的构造函数。

11.当有多个父类时,会按照派生类构造函数的初始化成员列表的顺序来调用父类的构造函数。

12.对基类成员和子对象成员的初始化必须在成员初始化列表中进行。

13.派生类构造函数必须对这三类成员进行初始化,其执行顺序为先调用基类构造函数,然后调用子对象的构造函数,最后调用派生类的构造函数。

14.当派生类有多个基类时,处于同一层次的各个基类的构造函数的调用顺序取决于定义派生类时声明的顺序。

15.当派生类中有多个子对象时,各个子对象构造函数的调用顺序也取决于在派生类中定义的顺序。

16.基类的构造函数定义了一个或多个参数时,派生类必须定义构造函数。

17.基类中定义了缺省构造函数或根本没有定义任何一个构造函数,在派生类构造函数的定义中可以省略对基类构造函数的调用。

18.基类对象 = 派生类对象,注意,反向的赋值是不允许的

19.继承中的二义性:通过域限定符来解决,也可以通过虚基类来访问。

20.代码如下:

   #include "Utility.h"

 

class CFather

{

public:

int m_iAge;

public:

CFather()

{

cout<<"CFather类的构造函数被调用......"<<endl;

m_iAge = 50;

}

CFather(int _age)

{

cout<<"CFather类的构造函数被调用......"<<endl;

m_iAge = _age;

}

~CFather()

{

cout<<"CFather类的析构函数被调用......"<<endl;

}

int getAge()const{return m_iAge;};

};

class CMother

{

public:

int m_iAge;

float m_fWeight;

public:

CMother(float _weight,int _age)

{

cout<<"CMother类的构造函数被调用......"<<endl;

m_fWeight = _weight;

m_iAge = _age;

}

~CMother()

{

cout<<"CMother类的析构函数被调用......"<<endl;

}

float getWeight()const{return m_fWeight;}

int getAge()const{return m_iAge;}

};

class CSon:public CFather ,public CMother

{

public:

int m_iAge;

public:

CSon(): //在子类的构造函数成员初始化列表中明确调用父类的构造函数

CFather(),

CMother(52.25f,40)

{

cout<<"CSon类的构造函数被调用!!!"<<endl;

}

//----重载构造函数----

CSon(int _sonAge,int _fatherAge,int _motherAge,float _weight):

CFather(_fatherAge),

CMother(_weight,_motherAge),

m_iAge(_sonAge)

{

cout<<"CSon类的构造函数被调用!!!"<<endl;

}

~CSon()

{

cout<<"CSon类的析构函数被调用!!!"<<endl;

}

int getAge()const{return m_iAge;}

};

void main()

{

CSon * pSon = new CSon(22,54,50,68.5f);

cout<<"SonAge = "<<pSon->getAge()<<endl;

cout<<"FatherAge = "<<pSon->CFather::getAge()<<endl;

cout<<"MotherAge = "<<pSon->CMother::getAge()<<endl;

if(pSon)

{

delete pSon;

pSon = NULL;

}

/*

    具有继承关系的一组类中,构造、析构、

成员初始化列表他们的调用顺序是:

1、子类的构造函数成员初始化列表

2、父类的构造函数成员初始化列表

3、父类的构造函数体

4、子类的构造函数体

5、子类的析构函数

6、父类的析构函数

当我们的父类有构造函数参数时,应该在子类的构造函数

成员初始化列表中明确调用父类带参数的构造函数。

*/

 

 

system("pause");

}

21.隐藏是指派生类的函数屏蔽了与其同名的基类函数。

22.当基类中的函数与派生类函数同名时,默认调用的是派生类的函数。解决办法是加上域限定符。

23.虚基类:当BC继承A并且D继承BC时,当D去访问A中的数据时会产生二义性,因为BC中有两份A的数据,解决的办法是虚继承,在继承方式前加上virtual构成虚继承。这样从基类拷贝过来的A的数据只有一份。

24. 虚继承: class <类名> : virtual <继承方式> <基类名>

25.当继承方式中有虚继承时,在调用构造函数时会优先调用虚基类的构造函数。

26.代码如下:

    #include "Utility.h"

class CZooAnimal

{

public:

CZooAnimal(){cout<<"CZooAnimal构造函数called..."<<endl;}

~CZooAnimal(){cout<<"CZooAnimal析构函数called..."<<endl;}

};

class CBear : public CZooAnimal

{

public:

CBear():

    CZooAnimal()

{

cout<<"CBear构造函数called..."<<endl;

}

~CBear(){cout<<"CBear析构函数called..."<<endl;}

};

class CEndangered

{

public:

CEndangered(){cout<<"CEndangered构造函数called..."<<endl;}

~CEndangered(){cout<<"CEndangered析构函数called..."<<endl;}

};

class CPanda : public CBear , public CEndangered

{

public:

CPanda():

    CBear(),

CEndangered()

{

cout<<"CPanda构造函数called..."<<endl;

}

~CPanda(){cout<<"CPanda析构函数called..."<<endl;}

};

class CFather

{

public:

virtual void printNumber(){cout<<"1"<<endl;}

};

class CSon : public CFather

{

public:

void printNumber(/*int _iValue*/){cout<<"2"/*_iValue*/<<endl;}

};

void main()

{

CPanda * pPanda = new CPanda();

if(pPanda)

{

delete pPanda;

pPanda = NULL;

}

CSon son;

//son.printNumber();//反例:子类中具有与基类同名的函数,

//尽管参数不同,也不能构成在子类中的

//“函数重载”,而是将基类中的同名函数

//覆盖掉。

son.printNumber(/*20*/);

system("pause");

}

#include "Utility.h"

//--爷爷类:交通工具--

class CVehicle

{

public:

int m_iWeight;

public:

void setWeight(int _weight){m_iWeight = _weight;}

virtual void showMe(){cout<<"我是交通工具类"<<endl;}

};

//--父类1:汽车--

class CCar : virtual public CVehicle

{

public:

float m_fAird; //排量

public:

void showMe(){cout<<"我是汽车"<<endl;}

};

//--父类2:船--

class CBoat : virtual public CVehicle

{

public:

float m_fTonnage; //排水量

public:

void showMe(){cout<<"我是船"<<endl;}

};

//--子类:水路两栖汽车--

class CSL_Car : public CCar,public CBoat

{

public:

void showMe(){cout<<"我是水路两栖车"<<endl;}

};

void main()

{

CSL_Car temp;

temp.showMe();

temp.setWeight(20);

cout<<temp.m_iWeight<<endl;

system("pause");

}

0 0