这章内容很重要,而且也很多新的概念出现。主要包括:
1,类的继承和派生的基本概念;
2,派生类的构造函数/释放函数与对象的创建;
3,多基派生及虚基类;
4,类层次中的作用域及类转换问题;
5,虚函数、纯虚函数和抽象类
----------------------------------------------------------------------------------------------------------------------
一)类的继承(inheritance)和派生(derivation)的基本概念
在一个类层次结构中,下一层类(子类)的描述要使用上一层类(父类)的属性和行为,这一特点称为继承;以既有类(基类)为基础导出(定义)新的类(派生类)的过程称为派生。
派生类格式:
class 派生类名:派生方式 基类名{
private:
新增私有成员声明语句表列
public:
新增公开成员声明语句表列
};
派生方式有三种:public派生和private派生和protected派生。
形象起见,类内私有成员可以理解成是一种处于底层的东西,属于只有自己才能知道的秘密,蛇仍保持着独有的私有性,只有本类成员函数和友元函数才可以调用。所以一般情况下,不论哪种派生方式,派生类都是不能访问到基类私有成员的(除非采用特殊方式)。从另一种角度上,也可以说派生类是基类中非私有成员的扩展,不仅可以将基类中的非私有属性/方法变为自己所用,还可以使用自身新增的任何属性/方法。
private派生,protected派生,public派生就如同把秘密丢到陆海空,埋进地下的秘密只有埋者才会知道,而抛进大海的秘密除了他一个人知道外,海水也知道的(这时海水相当于派生类的方法函数),而放到天空中的秘密地球人都看到了。另外一种方法就是用图示法,共三层,上层表示public,中层表示protected,下层表示private:
例:D:public C:private B:public A
D<--C /B<-A (public)
/ (protected)
__/ (private)
从图示可以看出:D的访问权限只有D和C的非private函数;而C对象访问权限为C内非private成员,C内方法函数访问权限为C所有成员及B和A的非private成员。
例:D:private C:public B: private A
D /C<-B /A
/ /
___/ __/
从图示可以看出:D类对象访问权限是D非private成员,D类方法函数访问权限是D内所有成员及C和B的非private成员。
二)派生类的构造函数/释放函数与对象的创建
类层次结构中成员函数是共享的,而数据成员是分别存储的。每一个类对象中,不仅要存储自己类中定义的数据成员,还要存储其先辈中定义的数据成员。但是构造函数与释放函数是不能继承的,为此对派生类必须重新定义构造函数与释放函数。
派生类对象的创建有两种方式:全部常数参数创建,常数参数+基类对象创建。
#include <iostream.h>
#include <string.h>
class Hard{
protected:
char bodyname[20];
public:
Hard(char *bdnm)
{cout<<"con H"<<endl;
strcpy(bodyname,bdnm);
}
Hard(Hard & abody)
{cout<<"copy H"<<endl;
strcpy(bodyname,abody.bodyname);
}
void print()
{cout<<"Body_Name:"<<bodyname<<endl;
}
};
class Soft{
protected:
char os[10];
public:
Soft(char *o)
{cout<<"con F"<<endl;
strcpy(os,o);
}
Soft(Soft & asoft)
{cout<<"copy F"<<endl;
strcpy(os,asoft.os);
}
void print()
{cout<<"os:"<<os<<endl;
}
};
class Language{
protected:
char lang[15];
public:
Language(char *lg)
{cout<<"con L"<<endl;
strcpy(lang,lg);
}
Language(Language & aLanguage)
{cout<<"copy L"<<endl;
strcpy(lang,aLanguage.lang);
}
void print()
{cout<<"lange:"<<lang<<endl;
}
};
class System:public Hard,public Soft,public Language{
protected:
char owner[10];
public:
System(char *ow, char *bn, char *o, char *lg):Hard(bn),Soft(o),Language(lg)
{cout<<"con S"<<endl;
strcpy(owner,ow);
}
System(char *ow,Hard abody, Soft asoft, Language aLanguage):Hard(abody),Soft(asoft),Language(aLanguage)
{cout<<"copy S"<<endl;
strcpy(owner,ow);
}
void print()
{cout<<"owner:"<<owner<<endl
<<"hard:"<<bodyname<<endl
<<"soft:"<<os<<endl
<<"Language:"<<lang<<endl;
}
};
void main()
{System bsystem("Wang","IBM PC","PC DOS","Ture BASIC");
bsystem.print();
cout<<"OK!"<<endl<<endl;
Hard abody("AST 386 sx/16");
Soft asoft("PC DOS");
Language aLanguage("Borland C++");
cout<<endl<<endl;
//System asystem("Zhang",abody,asoft,aLanguage); //copyL,copyF,copyH
//System asystem("Zhang",abody,asoft,"Borland C++"); //conL,copyF,copyH
System asystem("Zhang",abody,"PC DOS",aLanguage); //copyL,conF,copyH
asystem.print();
}
该示例中包括了两种创建方法,当派生类对象创建时,首先扫描参数列表见红体字,如果其中未发现基类对象,将转到绿色字部分先执行基类构造函数,再执行派生类构造函数进行初始化。而如果在形参中发现基类对象,则会从右到左根据情形来调用基类的复制构造函数或构造函数(为什么从右到左呢,因为扫描从左到右的,扫描到最后才能确定参数列表中有多少基类对象参数,按栈的FILO规则,调用基类复制构造函数必然是从右到左,,这是我个人的理解),然后再加到绿体字部分执行基类函数的构造函数;最后再执行派生类构造函数进行初始化。
三)多基派生及虚基类;