三. 虚函数使用技巧
3.1 private的虚函数
考虑下面的例子:
class="tags" href="/tags/CLASS.html" title=class>class A
{
public:
void foo() { bar();}
private:
virtual void bar() { ...}
};
class="tags" href="/tags/CLASS.html" title=class>class B: public A
{
private:
virtual void bar() { ...}
};
在这个例子中c;虽然bar()在A类中是private的c;但是仍然可以出现在派生类中c;并仍然可以与public或者protected的虚函数一样产生多态的效果。并不会因为它是private的c;就发生A::foo()不能访问B::bar()的情况c;也不会发生B::bar()对A::bar()的override不起作用的情况。
这种写法的语意是:A告诉Bc;你最好override我的bar()函数c;但是你不要管它如何使用c;也不要自己调用这个函数。
3.2 构造函数和析构函数中的虚函数调用
一个类的虚函数在它自己的构造函数和析构函数中被调用的时候c;它们就变成普通函数了c;不“虚”了。也就是说不能在构造函数和析构函数中让自己“多态”。例如:
class="tags" href="/tags/CLASS.html" title=class>class A
{
public:
A() { foo();} // 在这里c;无论如何都是A::foo()被调用!
~A() { foo();} // 同上
virtual void foo();
};
class="tags" href="/tags/CLASS.html" title=class>class B: public A
{
public:
virtual void foo();
};
void bar()
{
A * a = new B;
class="tags" href="/tags/DELETE.html" title=delete>delete a;
}
如果你希望class="tags" href="/tags/DELETE.html" title=delete>delete a的时候c;会导致B::foo()被调用c;那么你就错了。同样c;在new B的时候c;A的构造函数被调用c;但是在A的构造函数中c;被调用的是A::foo()而不是B::foo()。
3.3 多继承中的虚函数 3.4 什么时候使用虚函数
在你设计一个基类的时候c;如果发现一个函数需要在派生类里有不同的表现c;那么它就应该是虚的。从设计的角度讲c;出现在基类中的虚函数是接口c;出现在派生类中的虚函数是接口的具体实现。通过这样的方法c;就可以将对象的行为抽象化。
以class="tags" href="/tags/SheJiMoShi.html" title=设计模式>设计模式[2]中Factory Method模式为例c;Creator的factoryMethod()就是虚函数c;派生类override这个函数后c;产生不同的Product类c;被产生的Product类被基类的AnOperation()函数使用。基类的AnOperation()函数针对Product类进行操作c;当然Product类一定也有多态(虚函数)。
另外一个例子就是集合操作c;假设你有一个以A类为基类的类层次c;又用了一个std::class="tags" href="/tags/VECTOR.html" title=vector>vector来保存这个类层次中不同类的实例指针c;那么你一定希望在对这个集合中的类进行操作的时候c;不要把每个指针再cast回到它原来的类型(派生类)c;而是希望对他们进行同样的操作。那么就应该将这个“一样的操作”声明为virtual。
现实中c;远不只我举的这两个例子c;但是大的原则都是我前面说到的“如果发现一个函数需要在派生类里有不同的表现c;那么它就应该是虚的”。这句话也可以反过来说:“如果你发现基类提供了虚函数c;那么你最好override它”。
附:C++中的虚函数和纯虚函数用法
1.虚函数和纯虚函数可以定义在同一个类(class="tags" href="/tags/CLASS.html" title=class>class)中c;含有纯虚函数的类被称为抽象类(abstract class="tags" href="/tags/CLASS.html" title=class>class)c;而只含有虚函数的类(class="tags" href="/tags/CLASS.html" title=class>class)不能被称为抽象类(abstract class="tags" href="/tags/CLASS.html" title=class>class)。
2.虚函数可以被直接使用c;也可以被子类(sub class="tags" href="/tags/CLASS.html" title=class>class)重载以后以多态的形式调用c;而纯虚函数必须在子类(sub class="tags" href="/tags/CLASS.html" title=class>class)中实现该函数才可以使用c;因为纯虚函数在基类(base class="tags" href="/tags/CLASS.html" title=class>class)
只有声明而没有定义。
3.虚函数和纯虚函数都可以在子类(sub class="tags" href="/tags/CLASS.html" title=class>class)中被重载c;以多态的形式被调用。
4.虚函数和纯虚函数通常存在于抽象基类(abstract base class="tags" href="/tags/CLASS.html" title=class>class -ABC)之中c;被继承的子类重载c;目的是提供一个统一的接口。
5.虚函数的定义形式:virtual {method body} ;纯虚函数的定义形式:virtual { } = 0; 在虚函数和纯虚函数的定义中不能有static标识符c;原因很简单c;被static修饰的函数在编译时候要求前期bind,然而虚函数却是动态绑定(run-time bind)c;而且被两者修饰的函数生命周期(life recycle)也不一样。
6.如果一个类中含有纯虚函数c;那么任何试图对该类进行实例化的语句都将导致错误的产生c;因为抽象基类(ABC)是不能被直接调用的。必须被子类继承重载以后c;根据要求调用其子类的方法。
以下为一个简单的虚函数和纯虚寒数的使用演示c;目的是抛砖引玉!
#include
//father class="tags" href="/tags/CLASS.html" title=class>class
class="tags" href="/tags/CLASS.html" title=class>class Virtualbase
{
public:
virtual void Demon()= 0; //prue virtual function
virtual void Base() {cout<<"this is farther class="tags" href="/tags/CLASS.html" title=class>class"<};
//sub class="tags" href="/tags/CLASS.html" title=class>class
class="tags" href="/tags/CLASS.html" title=class>class SubVirtual :public Virtualbase
{
public:
void Demon() { cout<<" this is SubVirtual!"< void Base() {
cout<<"this is subclass="tags" href="/tags/CLASS.html" title=class>class Base"<};
/* instance class="tags" href="/tags/CLASS.html" title=class>class and sample */
void main()
{
Virtualbase* inst = new SubVirtual(); //multstate pointer
inst->Demon();
inst->Base();
// inst = new Virtualbase();
// inst->Base()
return ;
}
本文来自CSDN博客c;转载请标明出处:http://blog.csdn.net/dchcuckoo/archive/2005/10/14/504004.aspx