在学习本章时我们一定要注意代码段我标明的注释
1.多态使用条件
1.必须用基类的引用或者指针去调用虚函数
2.被调用的函数必须是虚函数,而且完成了重写/覆盖
using namespace std;
#include<iostream>
class person
{
public:
virtual void Buyticket()//重写 virtual是关键字,用来定义虚函数
{
cout << "全价购票" << endl;
}
private:
int ID;
};
class student : public person
{
public:
virtual void Buyticket()//重写 virtual是关键字,用来定义虚函数
{
cout << "半价购票" << endl;
}
private:
int IDcard;
};
int main()
{
student ST;
person* PS = &ST;//用基类的指针或引用调用虚函数
PS->Buyticket();
}
1.虚函数
在内部成员函数名前面加virtual关键字,那么这个函数便成了这个类的虚函数
2.虚函数的重写与覆盖
多态的构成需要各个派生类和基类都重写虚函数
重写就是,在子类里面写一个与父类要实现多态的函数名相同的函数
3.虚函数的细节问题
当我们不再子类里写virtual时我们同样能构成多态
using namespace std;
#include<iostream>
class person
{
public:
virtual void Buyticket()
{
cout << "全价购票" << endl;
}
private:
int ID;
};
class student : public person
{
public:
void Buyticket()
{
cout << "学生半价购票" << endl;
}
private:
int IDcard;
};
class adult :public person
{
public:
void Buyticket()
{
cout << "成人全价购票" << endl;
}
private:
int creditcard;
};
int main()
{
student ST;
person* PS = &ST;//用基类的指针或引用调用虚函数
adult ad;
person* PS1 = &ad;
PS->Buyticket();
PS1->Buyticket();
}
不过这种实现会有缺陷,我们来看一个代码
class A
{
public:
virtual void func(int val = 1)
{
std::cout << "A->" << val << std::endl;
}
virtual void test()
{
func();
}
};
class B : public A
{
public:
void func(int val = 0)
{
std::cout << "B->" << val << std::endl;
}
};
int main()
{
B* p = new B;
p->test();
return 0;
}
按照我们之前的思想这个代码是不是应该输出的是B->0才对
不过因为我们没有在子类函数加virtual所以导致了这种情况
因为如果我们不加virtual那么继承方式如下图所示
因为B的函数不是虚函数,所以在继承时会把A的函数体替换B
4.析构函数的重写
子类继承父类,它们的析构函数会构成重写,因为编译器对析构函数做了特殊处理,在编译时会将析构函数统一处理成destructor。所以它们的函数名相同。
所以当我要使用多态时重新写类的析构函数时我们需要在析构函数前加virtual,否则在程序结束后,将不会调用子类的析构函数,从而导致内存泄漏
class A
{
public:
~A()
{
cout << " ~A() " << endl;
}
};
class B : public A
{
public:
~B()
{
cout << " ~B() " << endl;
}
};
int main()
{
A* p1 = new B;
A* p2 = new A;
delete p1;
delete p2;
}
class A
{
public:
virtual~A()
{
cout << " ~A() " << endl;
}
};
class B : public A
{
public:
~B()
{
cout << " ~B() " << endl;
}
};
int main()
{
A* p1 = new B;
A* p2 = new A;
delete p1;
delete p2;
}
5.override和final
1.override
用法:判断一个子类的函数是否与父类构成重写
2.final
用法:使一个函数不能被重写
6.纯虚函数和抽象类
在需要设置纯虚函数后面写=0,那么这个函数就被定义为纯虚函数(不需要被实现,没什么意义),纯虚函数需要在被派生类继承时才定义,拥有纯虚函数的类叫做抽象类,而抽象类不能实现对象,所以派生类想要定义对象,必须帮助基类去实现纯虚函数。
PS:多态的原理,记住虚函数表和虚函数指针