1:协变
定义:
派生类重写基类时,两个虚函数的返回值类型不同,基类返回的是基类对象的**指针或者引用,**派生类返回派生类对象的指针或者引用,就称为发生了协变。我们认为协变是一种多态的特例
我们来看一组程序
using namespace std;
class Base
{
public:
Base()
{
cout << "Base" << endl;
}
virtual void fun()
{
cout << "Base" << endl;
}
virtual Base* Test()
{
cout << "Base()" << endl;
return this;
}
private:
int m_a;
int m_b;
};
class A :public Base
{
public:
A()
{
cout << "A" << endl;
}
void fun()
{
cout << "A" << endl;
}
A * Test()
{
cout << "A()" << endl;
return this;
}
private:
int a;
int b;
};
int main()
{
A a;
Base *p = &a;
p->Test();
system("pause");
return 0;
}
本身这个Test()是不满足多态的,因为返回值是不一样的,不满足我们重写的三同(返回值,函数名,形参),按理说是不能调动子类方法的,但是这里是可以调用子类方法的,就称为协变。
2:析构函数重写
如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同,但是依旧可以重写。可以理解成编译器对这个名字做了优化处理,编译后析构函数的名称统一处理成destructor。
这个时候我们就想,我为什么要重写析构函数?
如果我们在堆上申请一个类
class Base
{
public:
void fun()
{
cout << "Base" << endl;
}
Base()
{
cout<<"Base"<<endl;
}
~Base()
{
cout << "~Base" << endl;
}
private:
int m_a;
int m_b;
};
class A :public Base
{
public:
A()
{
cout << "A" << endl;
}
void fun()
{
cout << "fun" << endl;
}
~A()
{
cout << "~A" << endl;
}
void print()
{
cout << "print" << endl;
}
private:
int a;
int b;
};
int main()
{
Base* p = new A(); //动态申请需要手动释放
delete p;
return 0;
}
我们看运行结果
我们可以看到,我们申请的是A的空间,但是却调用的是父类的析构函数,这就会导致我们的A空间里的部分没有被释放
怎么解决呢?
这就需要我们虚析构函数
我们需要在父类构造函数处加上virtual关键字
C++11提供了两个关键字检测是否重写
override //要求子类必须重写这个方法
final //使程序不能被重写
强转后调用
我们来看代码:
6 class Base
7 {
8 public:
9 void virtual Func()
10 {
11 cout<<"Base"<<endl;
12
13 }
14
15 };
16
17 class Derived : public Base
18 {
19 public:
20 void virtual Func()
21 {
22 cout<<"Derived "<<endl;
23
24 }
25
26 };
27
28 int main ()
29 {
30 Base* pBase = new Base();
31 pBase ->Func();
32 Derived * pDerived = (Derived*)pBase;
33 pDerived->Func();
W> 34 delete pBase;
35
36 pDerived = new Derived();
37 pBase = pDerived;
38 pBase->Func();
39
W> 40 delete pDerived;
41 return 0;
42
我们如果用父类指针指向一个子类,我们将这个父类指针强转成为子类指针类型,然后调用,调用的是父类。