所以存在一个问题:
A --------公共基类
/ \
B C -------中间子类
\ /
D --------汇聚子类
虚继承
virtual
virtual
class 类名:virtual 继承方式 类名 //中间子类,可多继承
{
中间子类自己的内容;
};
父类的指针或者引用,指向或者初始化子类的对象,调用子类对父类重写的函数,进而使用子类的功能。
virtual
虚析构函数 :如果把父类中析构函数设置成虚析构函数,那么子类拓展的空间就会被一起释放,虚析构函数也满足继承。
示例 :
#include
using namespace std;
class Person
{
private:
string name;
public:
Person() {}
Person(string name):name(name){}
virtual ~Person(){} //虚析构函数
};
class Stu:public Person
{
private:
int id;
public:
Stu() {}
Stu(string n, int id):Person(n),id(id){}
~Stu(){}
};
int main()
{
Person *ptr = new Stu("zhangsan", 1001);
delete ptr; //如果没有虚析构函数的话,只释放父类指针作用的空间,子类
//拓展的空间并没有得到释放,会造成内存泄漏。解决方案:虚析构函数
return 0;
}
当父类中的虚函数只用来被子类重写,并且没有需要去完成的功能,那么一般将该虚函数设置成纯虚函数。
格式:
virtual 函数返回值类型 函数名(形参列表) = 0 ; //纯虚函数
//纯虚函数 是在父类中声明,子类中实现
概念: 抽象类中至少有一个纯虚函数,抽象类不能具体的实例化一个对象,一般是用来被继承的。
不能实例化对象,只能执行子类对象
如果父类中有纯虚函数,表示父类是抽象类,
子类继承后,如果没有对父类中纯虚函数做重写,则子类也是一个抽象类,不能实例化一个对象。
例如 :
#include
using namespace std;
class A
{
private:
int a;
public:
virtual void show() = 0;//纯虚函数
};
class B :public A
{
private:
int b;
public:
};
int main()
{
//B a; 不能实例化一个对象
return 0;
}
虚函数和纯虚函数可以定义在同一个类中,含有纯虚函数的类被称为抽象类,而只含有虚函数的类不能被称为抽象类。
虚函数可以被直接使用,也可以被子类重载以后,以多态的形式调用,而纯虚函数必须在子类中实现该函数才可以使用,因为纯虚函数在基类有声明而没有定义。
虚函数和纯虚函数都可以在子类中被重载,以多态的形式被调用。
虚函数和纯虚函数通常存在于抽象基类之中,被继承的子类重载,目的是提供一个统一的接口。
虚函数的定义形式:virtual{};纯虚函数的定义形式:virtual { } = 0;在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时要求前期绑定,然而虚函数却是动态绑定,而且被两者修饰的函数生命周期也不一样。
template<typename T>
函数的定义
如 :
template <typename T>
T fun(T x, T y) //建立了一个通用的函数,实现数据类型之和
{
return x+y;
}
template -------> 创建模板
typename -------> 表明其后是一种数据类型,typename还可以用class代替
T -----> 表示数据类型,也可以用其他代替
调用时 :
cout << fun(1,2) << endl;
cout << fun(1.3,1.4) << endl;
cout << fun('0', '1') << endl;
template<typename T>
类的定义
template -------> 创建模板
typename -------> 表明其后是一种数据类型,typename还可以用class代替
T -----> 表示数据类型,也可以用其他代替
作用 :可以优雅的解决异常
实现步骤
try
包裹可能产生异常的地方throw
抛出异常try
后面的 catch
语句中接收异常,并在 catch
后的代码块中处理异常示例 :
#include
using namespace std;
int fun(int x, int y)
{
if(y!=0)
{
return x/y;
}
else
{
throw -1; //抛出异常
}
}
int main()
{
try
{
fun(9,0); //把可能发生异常的地方用try包裹起来
cout << "hello 啊" << endl;
}
catch (int e)
{
if(e == -1)
{
cout << "分母为0,不合法" << endl;
}
}
return 0;
}
比喻:
动物园的讲解员和动物表演
动物园里有一位讲解员,他会为每种动物表演做简单的介绍,如狮子、大象、猴子等。
提示:
在这个场景中,我们可以将动物比作是不同的类,而每种动物表演则是类中的函数。
讲解员则是一个基类,他可以根据每种动物的特点和表演,进行相应的介绍。
具体过程如下:
定义一个基类 Animal,其中有一个虛函数perform(),用于在子类中实现不同的表演行为。
#include
using namespace std;
// base_class
class Animal
{
private:
string name;
public:
Animal() {}
Animal(string name):name(name) {}
Animal(const Animal &other):name(other.name){}
Animal &operator=(const Animal &other){
name = other.name;
return *this;
}
virtual ~Animal(){}
virtual void perform() = 0;
string get_name(){
return this->name;
}
};
class Lion:virtual public Animal
{
public:
Lion() {}
Lion(string name):Animal(name) {}
Lion(const Lion &other):Animal(other){}
Lion &operator=(const Lion &other){
Animal::operator=(other);
return *this;
}
~Lion(){}
void perform() {
cout << Animal::get_name() + " : " << "河东狮吼" << endl;
}
};
class Elephant:virtual public Animal
{
public:
Elephant() {}
Elephant(string name):Animal(name) {}
Elephant(const Elephant &other):Animal(other){}
Elephant &operator=(const Elephant &other){
Animal::operator=(other);
return *this;
}
~Elephant(){}
void perform() {
cout << Animal::get_name() + " : " << "象群践踏" << endl;
}
};
class Monkey:virtual public Animal
{
public:
Monkey() {}
Monkey(string name):Animal(name) {}
Monkey(const Monkey &other):Animal(other){}
Monkey &operator=(const Monkey &other){
Animal::operator=(other);
return *this;
}
~Monkey(){}
void perform() {
cout << Animal::get_name() + " : " << "专业偷桃" << endl;
}
};
int main()
{
Animal *p = nullptr;
Lion l("狮子狗");
Elephant e("孟获");
Monkey m("孙猴子");
p = &l;
p->perform();
p = &e;
p->perform();
p = &m;
p->perform();
return 0;
}