什么是虚拟函数,我想如果你能马上用口头表达出来,那么你的基础不错。知道虚拟函数表吗?也许你已经看了很多书,了然于胸。其实很多时候并不需要看书,就可以体会到。然后什么是虚拟继承?也许听说过,但很少使用。其实使用虚拟继承,可以减轻你很多的痛苦。
看下面一个例子:
这里的例子尽可能的简单,关于虚拟函数。
class Father
{
public :
Father();
virtual void run();
virtual void say();
private:
static int i;
};
int Father::i=2;
Father::Father()
{
this->run();
}
void Father::run()
{
cout<<this->i<<endl;
this->say();
}
void Father::say()
{
cout<<"Father"<<endl;
}
class Child : public Father
{
public:
Child();
virtual void say();
private:
static int i;
};
注意,为了避免歧义,int i已经是private 类型了。
int Child::i=1;
Child::Child() : Father()
{
};
void Child::say()
{
cout<<"Child"<<endl;
}
下面的测试函数:
int main()
{
Father x;
Child y;
x.run();
y.run();
}
结果是什么?
有经验的人可能一眼就看出来了,我想,两个say,应该都没有问题。然后两个构造函数,他输出的是什么?
可能有人说,virtual void run();不是虚拟的吗?所以Child y调用构造函数时,当然输出的是1.
但马上就会有人反驳,应该是0?,因为Child::Child() : Father(),在构造Father()的时候,Child()还没有构造,当然,Child::i 的值不可能是1。
其实,结果不是这样,输出的是两个2!为什么? 虚拟函数失效了吗? 其实不是的,原因很简单,你要了解到i可不是虚拟的!而为什么是输出的是两个father?这里有两种说法,1:在构造father的时候,child没有构造,包括应该继承的虚拟函数,2:因为father()本身就是father类的函数。所以,调用father类的方法。 其实这两种说法是一致的。
下一个例子你会更加明白。这是一个完整的例子:
#include <iostream>
using namespace std;
class Father
{
public :
Father();
virtual void sayj();
protected:
int j;
};
void Father::sayj()
{
cout<<j<<endl;
}
class Child : public Father
{
public:
Child();
protected:
int j;
};
Child::Child() : Father()
{
this->j=10;
};
Father::Father()
{
this->j=100;
};
int main()
{
Father x;
Child y;
y.sayj();
}
结果是多少?100 而不是10, 这里,构造函数完成工作后,再调用sayj,他调用的的确是Child->sayj没错,是从Father继承过来的。但是,同样j不是虚拟的,由于Child中没有重写sayj,所以它会到“父类”中去找!一定要记住,虚拟函数不是宏,它很智能,它知道sayj来自父类,所以j也来自父类。
有时候只要仔细一些这些小的错误,就可以避免。
现在就出一道题目了,看看你是否理解了e。其实就是第一个例子的题目:
#include <iostream>
using namespace std;
class Father
{
public :
Father();
virtual void run();
virtual void say();
private:
static int i;
};
int Father::i=2;
Father::Father()
{
this->run();
}
void Father::run()
{
cout<<this->i<<endl;
this->say();
}
void Father::say()
{
cout<<"Father"<<endl;
}
class Child : public Father
{
public:
Child();
virtual void say();
private:
static int i;
};
int Child::i=1;
Child::Child() : Father()
{
};
void Child::say()
{
cout<<"Child"<<endl;
}
int main()
{
Father x;
Child y;
x.run();
y.run();
}
结果是多少?static 是故意迷惑你的。
结果是
2
Father
2
Father
2
Father
2
Child
对了吗?
为什么最后一个是"Child"? 因为say 在 Child 中重写过了!记住它很智能。
总结一下,在父类没有构造好前,子类不会构造,包括应该继承的虚拟函数!
即使构造了虚拟函数,虚拟函数不是宏!它做的不是简单的替换。
类变量不是虚拟的,构造函数不是虚拟的。(原理很简单,只是有时候其他比较有趣的理论也讲的通,增加了我们理解本质的难度)
好下面来说说虚拟继承。如果你了解了虚拟函数那么虚拟继承也就不难了。
很简单的例子。
class CWinBase : virtual protected IGetProc
class CPaint : virtual protected IGetProc,public CWinBase
好如果不用虚拟继承,那么IGetProc 类,会出现什么问题? 那就是ambiguous. 因为CWinBase中已经有了一个IGetProc了。(上面两个定义的方式并不好,不要学习。)这样做只是为了说明问题。为什么可以除去ambiguous,其实原理和虚拟函数是一样的。所谓虚拟,也就是当真正运行的时候,只有一个实体。原理嘛,就去看看Professional C++ ,里面说的很详细。
有时给自己一点提醒。不会犯可笑的错误