今天真是收获不少,又把虚函数折腾了一遍。看着看着,似乎多明白了点什么。照例,网上有朋友写的很好的总结文章,原链接:http://blog.youkuaiyun.com/jackystudio/article/details/11895639
原文:
虚函数的作用和意义,就不进行说明了,这里主要讨论下虚函数的用法。
1.典型的虚函数用法
可以看到,只有标识为virtual的函数才会产生运行时多态的效果。它只能借助指针或者引用来达到多态的效果。
- class A
- {
- public:
- virtual void f(){cout<<"A::f()";}//虚函数
- void g(){cout<<"A::g()";}//普通函数
- };
- class B :public A{
- public:
- virtual void f(){cout<<"B::f()";}
- void g(){cout<<"B::g()";}
- };
- class C :public A{
- public:
- virtual void f(){cout<<"C::f()";}
- void g(){cout<<"C::g()";}
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- A* pa=new B;//pa是指针喔
- pa->f(); // 调用B::f()
- pa->g(); // 调用A::g()
- delete pa;
- pa=new C;
- pa->f(); // 调用C::f()
- pa->g(); // 调用A::g()
- delete pa;
- pa=NULL;
- return 0;
- }
class A
{
public:
virtual void f(){cout<<"A::f()";}//虚函数
void g(){cout<<"A::g()";}//普通函数
};
class B :public A{
public:
virtual void f(){cout<<"B::f()";}
void g(){cout<<"B::g()";}
};
class C :public A{
public:
virtual void f(){cout<<"C::f()";}
void g(){cout<<"C::g()";}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pa=new B;//pa是指针喔
pa->f(); // 调用B::f()
pa->g(); // 调用A::g()
delete pa;
pa=new C;
pa->f(); // 调用C::f()
pa->g(); // 调用A::g()
delete pa;
pa=NULL;
return 0;
}
2.虚函数的默认继承
虚函数是默认继承virtual属性的,即使在子类中没有标识virtual。
- class A
- {
- public:
- virtual void f(){cout<<"A::f()";}
- };
- class B :public A{
- public:
- void f(){cout<<"B::f()";}//不加virtual了
- };
- class C :public B{
- public:
- void f(){cout<<"C::f()";}//也不加virtual了
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- A* pa=new B;
- pa->f(); // 调用B:f()
- delete pa;
- pa=new C;
- pa->f(); // 调用C:f()
- delete pa;
- pa=NULL;
- return 0;
- }
class A
{
public:
virtual void f(){cout<<"A::f()";}
};
class B :public A{
public:
void f(){cout<<"B::f()";}//不加virtual了
};
class C :public B{
public:
void f(){cout<<"C::f()";}//也不加virtual了
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pa=new B;
pa->f(); // 调用B:f()
delete pa;
pa=new C;
pa->f(); // 调用C:f()
delete pa;
pa=NULL;
return 0;
}
3.纯虚函数
纯虚函数和Java中的接口很像了,因为纯虚函数的存在导致了该类成了抽象类,它的主要作用就是规范接口,把实现留给子类。如果子类没有实现它的所有虚函数,那么该子类也是一个抽象类,通用不能进行实例化。
- class A
- {
- public:
- virtual void f()=0;//纯虚函数,导致该类为抽象类
- };
- class B :public A{
- public:
- virtual void f(){cout<<"B::f()";}
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- //A* pa=new A;//出错,不能实例化抽象类
- A* pa=new B;
- pa->f();//调用B::f()
- delete pa;
- pa=NULL;
- return 0;
- }
class A
{
public:
virtual void f()=0;//纯虚函数,导致该类为抽象类
};
class B :public A{
public:
virtual void f(){cout<<"B::f()";}
};
int _tmain(int argc, _TCHAR* argv[])
{
//A* pa=new A;//出错,不能实例化抽象类
A* pa=new B;
pa->f();//调用B::f()
delete pa;
pa=NULL;
return 0;
}
4.虚函数的调用模型
子类调用父类函数只有虚函数才得以执行,普通函数只会调用父类函数,不过要注意以下的h()可不能是构造函数或者析构函数,不然多态就无法实现。
- class A
- {
- private:
- virtual void f(){cout<<"A::f()"<<endl;}
- void g(){cout<<"A::g()"<<endl;}
- public:
- void h(){f();g();}
- };
- class B :public A{
- private:
- virtual void f(){cout<<"B::f()"<<endl;}
- void g(){cout<<"B::g()"<<endl;}
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- B b;
- b.h();//调用父类的h(),分别再调用f()和g()。f()为虚函数调用子类B::f(),g()为普通函数调用父类A::g()。
- return 0;
- }
class A
{
private:
virtual void f(){cout<<"A::f()"<<endl;}
void g(){cout<<"A::g()"<<endl;}
public:
void h(){f();g();}
};
class B :public A{
private:
virtual void f(){cout<<"B::f()"<<endl;}
void g(){cout<<"B::g()"<<endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
B b;
b.h();//调用父类的h(),分别再调用f()和g()。f()为虚函数调用子类B::f(),g()为普通函数调用父类A::g()。
return 0;
}
5.虚析构函数
虚构函数可以是虚函数,甚至是纯虚函数。如果它作为一个基类,那析构函数必须是虚函数。
而构造函数不能是虚函数。
- class A
- {
- public:
- A(){p_a=new char[1];cout<<"new 1"<<endl;}
- virtual ~A(){delete[] p_a;cout<<"delete 1"<<endl;}//正常
- //~A(){delete[] p_a;cout<<"delete 1"<<endl;}//异常,内存泄漏,~B()并没有被执行到
- private:
- char* p_a;
- };
- class B :public A{
- public:
- B(){p_b=new char[2];cout<<"new 2"<<endl;}
- ~B(){delete[] p_b;cout<<"delete 2"<<endl;}//能不能正确执行~B()成了关键
- private:
- char* p_b;
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- A* pa=new B;
- delete pa;
- return 0;
- }
class A
{
public:
A(){p_a=new char[1];cout<<"new 1"<<endl;}
virtual ~A(){delete[] p_a;cout<<"delete 1"<<endl;}//正常
//~A(){delete[] p_a;cout<<"delete 1"<<endl;}//异常,内存泄漏,~B()并没有被执行到
private:
char* p_a;
};
class B :public A{
public:
B(){p_b=new char[2];cout<<"new 2"<<endl;}
~B(){delete[] p_b;cout<<"delete 2"<<endl;}//能不能正确执行~B()成了关键
private:
char* p_b;
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pa=new B;
delete pa;
return 0;
}