c++支持编译时多态(静态多态)和运行时多态(动态多态),运算符重载和函数重载是编译时多态,而派生类和虚函数实现运行时多态。
运行时多态:在父类上声明虚函数,发生了多态。
父类的引用或指针指向子类的对象
虚函数
格式:
virtual 返回值 函数名();
例:
class Animal
{
public:
Animal()
{
}
//虚函数
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat:public Animal
{
public:
//子类写父类中的虚函数这种写法叫重写,重写必须返回值 参数个数 类型 顺序都相同
void speak()
{
cout << "猫在说话" << endl;
}
};
void doSpeak(Animal &Animal)
{
Animal.speak();
}
void test()
{
Animal* cat = new Cat;
doSpeak(*cat);
}
多态原理:
当父类中有了虚函数后,内部结构就发生了改变
内部多了一个vfprt(虚函数指针),指向vftable虚函数表
父类中结构 vtptr &Animal::speak
子类中 进行继承 会继承vfptr (虚函数指针)、 vftable(虚函数表)
在构造函数中,会将虚函数表指针指向自己的虚函数表
-
如果发生了重写,会替换掉虚函数表中原有的speak,改为&Cat::speak
多态优点
开发有原则 :开闭原则 ---对扩展开放 对修改关闭
利用多态实现 :利用后期扩展,结构性非常好,可读性高,多态内部结构复杂
缺点
效率稍微低一些
纯虚函数
如果父类中有了纯虚函数,子类继承父类,就必须要实现纯虚函数
如果父类中有了纯虚函数,这个父类就无法实例化对象了,通常又称为抽象类
格式:virtual 返回值 函数名()=0;
例:
class abstractCalculator
{
public:
//虚函数
/*virtual int getResult()
{
return 0;
}*/
//纯虚函数
virtual int getResult()=0;
void setVal1(int val1)
{
this->val1 = val1;
}
void setVal2(int val2)
{
this->val2 = val2;
}
int getVal1()
{
return val1;
}
int getVal2()
{
return val2;
}
int val1;
int val2;
};
class PlusCalculator :public abstractCalculator
{
public:
int getResult()
{
return val1 + val2;
}
};
class SubCalculator :public abstractCalculator
{
public:
int getResult()
{
return val1 - val2;
}
};
调用:
void show(abstractCalculator& a)
{
cout<<a.getResult()<<endl;
}
void test()
{
abstractCalculator * a=new PlusCalculator;
a->setVal1(10);
a->setVal2(20);
show(*a);
}
虚析构
普通析构不会调用子类的析构,所有可能会导致清理不干净
利用虚析构来解决这个问题。
格式:virtual ~类名()();
纯虚析构
纯虚构需要声明还需要实现,类内声明,类外实现。
如果出现了纯虚析构函数,这个类也算抽象类,不可以实例这个对象
格式:
virtual ~类名()()=0;