一.继承的概念
先举一个例子:儿子继承了父亲的基因,于是儿子有些特征会与父亲相同,但是儿子也会产生其他特征。c++中,一个类在得到了(共享得到)另一个类或者另几个类的成员变量和成员函数后,又增加新的功能,从而产生了新的类,该新类与另一个类或另几个类的关系,就叫继承。
该新类被称为子类(派生类),而另一类或者另几个类被称为父类(基类)。
如果父类只有一个就叫做单继承,如果有多个就叫做多继承。
单继承:
class 子类名:继承权限 父类名1
{
//类体
};
多继承:
class 子类名:继承权限 父类名1,继承权限 父类2...
{
//类体
};
二.继承的调用
1.子类Son继承了父类Father的成员变量a和成员函数function(),因此直接调用子类对象时,也会得到父类的内容。
#include"iostream"
using namespace std;
class Father
{
public:
int a = 50;
void function()
{
cout << "nice" << endl;
}
};
class Son : public Father
{
public:
void function1()
{
cout << "a=" << a << endl;
}
};
int main()
{
Son son;
son.function1();
son.function();
return 0;
}
2. 子类对象在用构造函数时,先是调用的父类的构造函数,然后才是子类的构造函数;
而在用析构函数析构函数时,先是调用的子类的析构函数,然后才是父类的析构函数。
#include "iostream"
using namespace std;
class Father
{
public:
Father()
{
cout << "Father start" << endl;
}
~Father()
{
cout << "Father end" << endl;
}
};
class Son : public Father
{
public:
Son()
{
cout << "Son start" << endl;
}
~Son()
{
cout << "Son end" << endl;
}
};
int main()
{
Son son;
return 0;
}
3.如果子类和父类有相同的变量或者函数,那么子类会自动隐藏(覆盖)父类与子类相同变量或者函数。(即子类与父类的变量或者函数不同时,子类才会继承父类的变量或者函数)
#include"iostream"
using namespace std;
class Father
{
public:
int a = 50;
void function1()
{
cout << "Father" << endl;
}
};
class Son : public Father
{
public:
int a = 100;
void function()
{
cout << "a=" << a << endl;
}
void function1()
{
cout << "Son" << endl;
}
};
int main()
{
Son son;
son.function();
son.function1();
return 0;
}
三.继承的权限
C++提供了public继承、private继承、protected继承三种继承方式,为了对继承加以限制。
继承权限/父类的成员 | 父类(基类)的public下的成员 | 父类(基类)的private下的成员 | 父类(基类)的protected下的成员 |
public继承 | 全部继承到子类的public属性下 | 没有继承到子类 | 成员变量继承到子类的protected属性下,成员函数没有继承到子类 |
private继承 | 全部继承到子类的private属性下 | 没有继承到子类 | 全部继承到子类的private属性下 |
protected继承 | 全部继承到子类的protected属性下 | 没有继承到子类 | 全部继承到子类的protected属性下 |
一般都是选择public(共有)继承。
四.虚继承
虚继承就是在继承权限前加上关键字virtual,为了解决多重继承(菱形继承)造成的二义性问题
class 子类名:virtual 继承权限 父类名1
{
//类体
};
1.菱形继承
两个子类继承了同一个父类,又有一个子类继承了这两个子类,这就叫做菱形继承。
菱形继承会造成数据冗余和二义性。
五.多态
根据字面意思,大致可以理解为多种形态(多种方法)。
C++里一般称为“一种接口,多种方法”,一种接口,指的是父类接口,多种方法表示父类中有方法并且子类中也有相同的方法(方法相同,实现的内容不同)
构成多态性的条件:
(1)两个类具有继承关系
(2)子类中必须重写父类的方法(子类方法中的内容与父类中的方法可以不一样)
(3)父类中的方法必须是虚函数
1.虚函数:相当于一个普通的成员函数,只是在函数前加了一个关键字virtual,就代表一个虚函数
virtual 返回值类型 函数名(参数列表)
{
//函数体
}
2.静态绑定(静态联编)
函数在定义和调用在编译阶段就确定了,称为静态绑定。
静态绑定的时候是根据类的指针对象或者是引用的类型来确定函数的调用,而不是通过类的指针或者是引用指向的对象的类型来确定。
3.动态绑定(动态联编)
函数的定义和调用在运行阶段才确定,称为动态绑定。
#include"iostream"
using namespace std;
class Father
{
public:
virtual void function2()//virtual虚函数,动态绑定
{
cout << "FATHER" << endl;
}
};
class Son:public Father
{
public:
virtual void function2()
{
cout << "SON" << endl;
}
};
int main()
{
Father father;
Father* fa;
Son son;
fa = &son;//如果没有虚函数,fa只与前面类型有关,即Father,fa->function2()只会调用父类的函数
//如果加入虚函数,fa指向子类,所以fa->function2()可以访问子类
fa->function2();
}
六.抽象类
现实世界中有些事物是不能实例化对象的,我们将这些事物声明为抽象类。抽象类只是给子类提供一个基类,在基类里只是对事物的一些描述,而没有具体的实现。
纯虚函数
在虚函数的声明后面加上“=0”,就表示该虚函数为纯虚函数,它是构成抽象类不可缺少的条件
class 类名//抽象类格式
{
virtual 返回值类型 函数名(参数列表)=0;//纯虚函数
} ;
注:1.抽象类只是给子类提供一个基类
2.抽象类不能实例化为对象
3.抽象类里只是描述了一些行为,但没有具体实现行为(纯虚函数),需要在子类中去重新实现抽象类的行为
#include"iostream"
using namespace std;
class Father
{
public:
virtual void function() = 0;//纯虚函数,表示这个类为抽象类,
//表示抽象类Father有function()方法,
//具体怎么实现要在子类实现
//在虚函数后面加上=0就是纯虚函数
};
class Son :public Father
{
public:
virtual void function()
{
cout << "Son" << endl;
}
};
int main()
{
//Father fa;这句是错的,Father是抽象类,不能实例化
Son son;
son.function();
return 0;
}
总结
继承在C++中也是一个重点,它是程序设计中使代码可以复用的一个重要手段,它呈现了程序设计的层次结构。对于以后的开发中,有广泛的用途,尤其是多继承,要注意使用,别搞出菱形继承。