文章目录
重载:函数名相同,参数列表不同、处在同一个作用域。
隐藏:基类和派生类当中 函数名相同 派生类会将基类的同名方法隐藏。如果想通过派生类对象访问基类的成员方法需要加作用域。
覆盖:基类和派生类中 函数的返回值 函数名 参数列表,而且基类的函数是virtual虚函数
继承
继承的作用:面向对象技术强调软件的可重用性。C++使用类的继承机制,解决了软件重用问题。
所谓继承就是在一个已存在的类的基础上建立一个新的类。已存在的类称为基类或父类。新建立的类称为派生类或子类。
一个新类从已有的类哪里获得其已有特性,这种现象称为类的继承。
单继承
一个派生类只从一个基类派生,称为单继承,这种继承关系 所形成的曾次是一个树形结构。
多重继承
一个派生类有两个或多个基类的称为多重继承。
派生
从已存在类(父类)产生一个新的子类,称为类的派生
派生类继承了基类的所有数据成员和成员函数.
一个基类可以派生出多个派生类,每一个派生类又可以作为基类再派生出新的派生类,因此基类和派生类是相对而言的。类的每一次派生,都继承类其基类的基本特征,同时又根据需要调整和扩充原有特征。
基类和派生类的关系:派生类是基类的具体化,而基类是派生类的抽象。
基类综合了派生类的公共特征,派生类则在基类的基础上增加了某些特性,把抽象编成具体的、实用的类型。
派生类的声明方式
class A
{
public:
int ma;
protected:
int mb;
private:
int mc;
};
class B : private A // 类B私有继承了类A
{
public:
void test() {
cout << mb << endl; }
int md;
protected:
int me;
private:
int mf;
};
在class后面的B是新建的类名,冒号后面的A是已经存在的基类。在A前有一个关键字private,用来表示基类A中的成员在派生类B中的继承方式。
继承方式包括:public(公用的),private(私有的)和protected(受保护的),如果不写,默认是private(私有的),而用struct 定义的类,如果不写,默认是public(公用的)。
派生类的构成
派生类中的成员
- 从基类继承过来的成员
- 自己增加的成员
从基类 继承的成员体现了派生类从基类继承而获得的共性,而新增加的成员体现了派生类的个性。正是这些新增加的成员体现了派生类与基类的不同,体现了不同派生类之间的区别。
构造一个派生类
(1)从基类接收成员
派生类把基类的全部的成员(不包括构造函数和析构函数)接收过来,不能选择接收其中一部分成员,而舍弃另一部分成员。
这就有可能出现一种情况:有些基类的成员在派生类是用不到的,但是也必须继承过来。这样就或造成数据的冗余,尤其是在多次派生之后,会在许多派生类对象中存在大量无用的数据,不仅浪费了大量的空间,而且在对象的建立、复制、赋值和参数的传递中,花费更多无谓的时间,降低了效率。所以,我们要根据根据派生类的需要合理的选择基类,使冗余量尽可能的小。
(2)调整从基类接收的成员
可以改变基类成员在派生类中的访问属性,这是通过指定继承方式实现的。
如可以通过继承把基类的公有成员指定位在派生类的访问属性为私有(派生类外不能访问)。
可以在派生类中声明一个与基类成员同名的成员,则派生类中的新成员户覆盖基类的同名成员。
(3)增加自己的成员
在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数,因为构造函数和析构是不能从基类继承的。
派生类成员的访问属性
确定基类的成员在派生类的访问属性,不仅要考虑对基类成员所声明的访问属性,还要考虑派生类所声明的对基类的继承方式,这两个因素共同决定基类成员在派生类的访问属性。
公用继承
可以看出公有继承唯一改变了不能访问基类的私有成员。
因为私有成员体现了数据的封装性,隐藏私有成员有利于测试、调试和修改系统。如果把基类所有成员的访问权限都原封不动地继承到派生类,使基类的私有成员在派生类中仍保持其私有性质,派生类成员能访问基类的私有成员,那么基类和派生类就没有界限了,这就破坏了基类的封装性。
要记住:保护私有成员是一条重要的原则!!!
私有继承
可以看出:既然声明为私有继承,就表示将原来能被外界引用的成员隐藏起来,不让外界引用,因此基类的公有成员和保护成员理所当然地成为派生类的私有成员。
对于不需要再往下继承的类的功能可以用私有继承方式把它隐藏起来,这样下一层的派生类就无法访问它的任何成员。
保护继承
由"protected"声明的成员称为“受保护的成员”。受保护的成员不能被类外访问。
保护成员和私有成员类似,但有一点和私有成员不同,保护成员可以被派生类的成员函数引用。
普通派生类的构造函数
前面已经说过,基类的构造函数是不能继承的,再声明派生类时,派生类并没有把基类的构造函数继承过来,因此对继承过来的基类成员的初始化工作也要由派生类的构造函数承担。所以在设计派生类的构造函数时,不仅要考虑派生类所增加的数据成员的初始化,还应当考虑基类的数据成员初始化。也就是说,在执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。
解决办法:在执行派生类的构造函数时,调用基类的构造函数。
class Base
{
public:
Base(int a) :ma(a) {
cout << "Base()" << endl; }
~Base() {
cout << "~Base()" << endl; }
void show() {
cout << "Base::show()" << endl; }
void show(int i) {