虚函数场景
一、最基本常见的
<pre name="code" class="cpp">#include <iostream>
using namespace std;
class CBase
{
public:
virtual void print()
{
cout<< "base" << endl;
}
void DoPrint()
{
print();
}
};
class CChild1: public CBase
{
public:
virtual void print() //virtual is optional;看类的成员函数是不是虚函数要看这个类的最顶层父类的同名同签名函数前有没有virtual,如果没有父类,则看自己前面有没有virtual;
{
cout<< "child1" << endl;
}
};
class CChild2: public CBase
{
public:
virtual void print() //virtual is optional;看类的成员函数是不是虚函数要看这个类的最顶层父类的同名同签名函数前有没有virtual,如果没有父类,则看自己前面有没有virtual;
{
cout<< "child2" << endl;
}
};
void DoPrint(CBase *base)
{
base->DoPrint();
}
int main()
{
CBase* base = new CBase();
CChild1* child1 = new CChild1();
CChild2* child2 = new CChild2();
DoPrint(child1);
DoPrint(child2);
DoPrint(base);
delete base;
base = child1; // 上面只是删除了base所指向的对象,base指针本身存在
base->print(); // 传统的虚函数的用法。
delete child1;
delete child2;
return 0;
}
运行结果:
二、需要对虚函数理解很透彻才能看懂的一个例子
#include <iostream>
using namespace std;
class BaseClass{
public:
BaseClass()
{
cout<<"BaseClass's constructor."<<endl;
}
virtual ~BaseClass()
{
cout<<"BaseClass's destructor."<<endl;
}
virtual void virtualFunction()
{
cout<<"BaseClass's virtualFunction"<<endl;
}
void test()
{
virtualFunction();
}
};
class DerivedClass:public BaseClass
{
public:
virtual void virtualFunction() //virtual is optional;
{
cout<<"DerivedClass's virtualFunction"<<endl;
}
};
int main()
{
cout << "Hello world!" << endl<<endl;
DerivedClass derive;
derive.test();
return 0;
}
运行结果:
三、你可以直接跳过的例子
#include <iostream>
using namespace std;
class A {
public:
void foo() {
cout << "A's foo()" << endl;
}
};
class B: public A {
public:
virtual void foo() {
cout << "B's foo()" << endl;
}
void bTest()
{
cout<<"B::bTest() "<<endl;
foo();
}
};
class C: public B {
public:
void foo() override { // override can only qualify virtual function.its function mainly lie on complication tips.
cout << "C's foo()" << endl;
}
};
int main() {
C cobj;
B *bptr = &cobj;
bptr->foo();
bptr->bTest();
A* aptr = &cobj;
aptr->foo();
}
运行结果:如果在A的foo前面加virtual则最后输出的是C’s foo();看类的成员函数是不是虚函数要看这个类的最顶层父类的同名同签名函数前有没有virtual,如果没有父类,则看自己前面有没有virtual;至于第三个输出C‘s foo()在第二个例子已经说明;
四
#include <iostream>
using namespace std;
class A {
public:
virtual void foo() {
cout << "A's foo()" << endl;
bar();
}
virtual void bar() {
cout << "A's bar()" << endl;
}
};
class B: public A {
public:
void foo() {
cout << "B's foo()" << endl;
A::foo();
}
void bar() {
cout << "B's bar()" << endl;
}
};
int main() {
B bobj;
A *aptr = &bobj;
aptr->foo();
A aobj = *aptr; // 这个例子想说的关键部分:将子类对象复制给基类对象,发生切割,就是只复制了两类中相同成员部分。
aobj.foo();
}
运行结果:
零碎知识点
1、看类的成员函数是不是虚函数要看这个类的最顶层父类的同名同签名函数前有没有virtual,如果没有父类,则看自己前面有没有virtual。所以,如果顶层父类的某一个函数前有virtual关键字,那么不管下面的子类的同名同签名函数前有没有virtual关键字,子类中的这个函数都是虚函数。
2、override只能用来限定虚函数,它的作用更多的是起编译检查作用,比如如果你在一个函数后面加override关键字,那么编译器就会检查这个函数和父类中的同名函数签名是不是一样,如果不一样就报错,如果没有override关键字,签名又是不一样的,并且在这个函数签名有virtual关键字,那么这个函数就成了一个新的虚函数。如果感兴趣,可以看下这篇博客关于override的博客。
在构造函数中调用虚函数From C++'s father's homepage
什么情况下析构函数该声明为virtual及其原因
首先你该看下C++之父BS对这个问题的解释。
总结如下:
1、当类中存在virtual函数的时候,就该把类的析构函数声明成virtual的。因为类中存在virtual函数表明设计者有把这个类作为基类的意图。
2、把可能作为基类的类的析构函数声明成virtual的原因是,当基类指针指向子类对象时,如果基类析构函数不是virtual的,delete指向子类对象的基类指针时将直接调用基类的析构函数而不是子类的析构函数,这样子类就存在资源没有释放的可能。将基类析构函数声明成virtual的,delete指向子类对象的基类指针时调用的是子类的析构函数(在子类的析构函数调用前会调用基类的析构函数),确保资源的释放。
虚函数表机制
更专业的解释请查看:Inside the C++ Object Model[Stanley B. Lippman] Chapter 4
原文:http://www.cnblogs.com/taoxu0903/archive/2008/02/04/1064234.html