一个虚拟函数的问题?

djhdu 2001-12-20 09:44:18
假设一个类用了虚拟函数,而且它还有派生类,并且派生类改写了它的虚拟函数,
现在,我定义一个基类的指针,然后执行虚拟函数,此时,这个虚拟函数应该是派生类的吧?我有点拿不准!
...全文
801 66 打赏 收藏 转发到动态 举报
写回复
用AI写文章
66 条回复
切换为时间正序
请发表友善的回复…
发表回复
eion 2002-01-30
  • 打赏
  • 举报
回复
看看这个例子:

现在你发神经要在家盖个动物园,你已经有了老虎罢,狗老弟,和你的猪老兄,当然,他们跟你一样都是动物Animal,而且你最喜欢他们变态的咆哮poar,而且他们都会咆哮,于是你就有了下面的代码:

Class Animal
{
protected:
char name[20];
public:
Animal(char* the_name){strcpy(name,the_name);}
~Animal(){}

virtual void poar()=0; //注意这个virtual,后面的函数都有
};

class Tiger : public Animal
{
public:
Tiger(char *the_name ) : Animal(the_name){}
virtual void poar(){cout<<"Tiger "<<name<<" is POARING: AOOOOOOOOOOOOOOO...."<<endl;}
};
class Dog : public Animal
{
public:
Dog(char *the_name ) : Animal(the_name){}
virtual void poar(){cout<<"DOG "<<name<<" is POARING: WangWangWang......."<<endl;}
};
class Pig : public Animal
{
public :
Pig(char *the_name ) : Animal(the_name){}
virtual void poar() {cout<<"PIG "<<name<<" is POARING: HengHengHeng......."<<endl;]
};

............................

这时你已经有了很多Animal了,于是你定义了你的宠物数组指针:
Animal *pMyAnimals[100];

当然你还没有100只宠物,只不过你先预留这么多空间来供以后不时之需,现在已经有了三种动物,于是你定义

int nAnimalNum = 3;
pMyAnimals[0] = new Tiger("小布什");
pMyAnimals[1] = new Dog("小泉");
pMyAnimals[2] = new Pig("布莱尔");
.........................

现在你想听听他们的咆哮声,于是:
for(int i=0;i<nAnimalNum;i++) pMyAnimals[i]->poar();

你得到
Tiger 小布什 is POARING: AOOOOOOOOOOOOOo.................
DOG 小泉 is POARING: WangWangWang................
PIG 布莱尔 is POARING: HengHengHeng...............
..........................
不同吧?

今天你脑壳上长了一个包,去买了一只雅虎【Yahoo】,于是,你又定义了一只宠物:
class Yahoo : public Animal
{
public:
Yahoo(char *the_name ) : Animal(the_name){}
virtual void poar() {cout<<"Yahoo "<<name<<"is POARING: Yahoo Yahoo Yahoo ...."<<endl;}
};

并在你的动物园内添加了一只雅虎
pMyAnimals[nAnimalNum++]= new Yahoo("跳槽");

然后再听他们美妙的叫唤声:
for(int i=0;i<nAnimalNum;i++) pMyAnimals[i]->poar();

你得到
Tiger 小布什 is POARING: AOOOOOOOOOOOOOo.................
DOG 小泉 is POARING: WangWangWang................
PIG 布莱尔 is POARING: HengHengHeng...............
..........................
Yahoo 跳槽 is POARING: Yahoo Yahoo Yahoo..........
..............................

好听吧?

这就是多态的一个最有用的例子~~~~~~~~~~~~~~~~~~~~~~~~~

Martens 2002-01-30
  • 打赏
  • 举报
回复
domainboy(chg)说得很对呀!
基类指针指向派生类时,如果调用的函数是基类和派生类都有的,但是这个函数不是以虚拟函数的状态存在的话,就调用基类的函数,也就是所谓的根据指针类型调用函数。如果调用的函数是虚函数的话,当然是调用派生类的函数了!这正是虚拟函数的妙处啊!
wsa_socket 2002-01-30
  • 打赏
  • 举报
回复
to:thomas269(Thomas) 
你说的内存中的类存储情况能否给解释一下?象类名、类函数代码、虚函数等, c++中类本身或者说编译器具体怎么个存储管理规则?
pinel 2002-01-30
  • 打赏
  • 举报
回复
这个贴子生命力够强,收藏,不过不明白大家为什么不拿程序试一下,很明白的事情
domainboy 2002-01-30
  • 打赏
  • 举报
回复
这是c++的多态问题.每个有虚函数的类,多有一个虚拟函数表(VIRTUAL TABLE),当一个指向基类的指针调用其中一个虚函数时,只需在这个表里查询到相应的函数,然后执行即可.当你在其派生类中重新定义某个虚函数,你定义的虚函数会更新VIRTUAL TABLE中的相应项,所以指针会调用派生类中重新定义的那个.

诸位,我说的是否对?
truestone 2002-01-30
  • 打赏
  • 举报
回复
和指针指向的对象有关,仅与对象有关!!
nise 2002-01-30
  • 打赏
  • 举报
回复
G--^^Z
bioinfomatics 2002-01-30
  • 打赏
  • 举报
回复
同意楼上的,主要是内存存放
nise 2002-01-30
  • 打赏
  • 举报
回复
eion(电离子) 
hahaha,,you are funny.
wsa_socket 2002-01-30
  • 打赏
  • 举报
回复
各位不防再彻底一点,请描述一下内存中的类存储情况?象类名、类函数代码、虚函数等, c++中类本身或者说编译器具体怎么个存取管理规则?基类与派生类之间的存取及运行期关系?
herohowk 2002-01-04
  • 打赏
  • 举报
回复
是派生的, 虚拟函数和重载函数是两个概念,虚拟函数的用途是什么? 和不虚拟的重载有什么区别? 不虚拟的重载函数由指针的类型决定, 而虚拟的重载函数由new的对象决定
airou 2002-01-04
  • 打赏
  • 举报
回复
如果你的指针是指向基类的,那么就是调用基类的函数

如果你的指针是一个指向派生类的基类指针,那么调用的是派生类的函数
humeiyixiao 2002-01-04
  • 打赏
  • 举报
回复
真是个热门问题!
thomas269 2001-12-28
  • 打赏
  • 举报
回复
你自己試試是基類還是派生, 事實勝於雄辯
kuhx 2001-12-25
  • 打赏
  • 举报
回复
不是,如果你的指针是一个基类指针,那就是调用基类的函数
xtky_limi 2001-12-22
  • 打赏
  • 举报
回复
旁听
wx_xuan 2001-12-22
  • 打赏
  • 举报
回复
如果指针指向基类对象就是基类的,如果派生类对象,就是派生类的
thomas269 2001-12-22
  • 打赏
  • 举报
回复
其實上面的都還未完全說明了派生和基類之間的關係, 再看
#include <stdio.h>

class base
{
public:
virtual void print() { printf("base\n");};
};

class abc : public base
{
private:
char *str;
public:
abc(char *s)
{
str = s; // 不能這樣做的, 這裡是作test
}
virtual void print()
{
printf("%s\n", str);
}
};

int main()
{
abc a("I am abc");
a.print();
((abc*)&a)->print();
return 0;
}
你又一次發展現, 兩個print都是I am abc, 這又為什麼?
和前一樣, base的結構沒有改變, 仍是:
struct base
{
void (*print)();
};
但派生的結構改變了, 變成:
struct 派生
{
void (*print)();
char *str;
};
在a.print中, 不用多說, 對派生的調用自然正確
但在((base*)&a)->print()中又如何呢?
其實base和派生的結構是基本相同, 只是在最後, 記著是最後加入了派生的成員str, 而a的*&a根本都時同一個實體, 即用同一內存空間, 對base而言, 派生的結構和base是完全一樣的, 但在調用print時, 如前所說, print已被改成派生的print, 所以實際上仍是對派生的調用, 所以他就能見到派生的成員str, 自然亦能print 出I am abc.
thomas269 2001-12-22
  • 打赏
  • 举报
回复
以下是三個例子在內存中的情況
class abc
{
private:
char a, b;
public:
char c;
abc() { a = 'a'; b = 'b'; c = 'c'; }
};
class efg : public abc
{
private:
char e;
public:
char f, g;
abc() { e = 'e'; f = 'f'; g = 'g'; }
};
size abc=3, size efg=6
61 62 63 abc
61 62 63 65 66 67 abcefg
#############################################################
class abc
{
private:
char a, b;
public:
char c;
abc() { a = 'a'; b = 'b'; c = 'c'; }
virtual void v() {};
};
class efg : public abc
{
private:
char e;
public:
char f, g;
efg() { e = 'e'; f = 'f'; g = 'g'; }
virtual void v() {};
};
size abc=8, size efg=12
1C 00 42 00 61 62 63 CC ..B.abc. // abc
20 00 42 00 61 62 63 CC 65 66 67 CC C0 .B.abcÌefgÌ // efg
#############################################################
class abc
{
private:
char a, b;
public:
char c;
abc() { a = 'a'; b = 'b'; c = 'c'; }
virtual void v() {};
};
class efg
{
private:
char e;
public:
char f, g;
efg() { e = 'e'; f = 'f'; g = 'g'; }
};
class xyz : public abc, public efg
{
public:
char x, y, z;
xyz() { x = 'x'; y = 'y'; z = 'z'; }
};
size abc=8, size efg=3, size xyz=16
3C 00 42 00 61 62 63 CC <.B.abcÌ
65 66 67 CC efg.
40 00 42 00 61 62 63 CC 65 66 67 78 79 7A CC CC @.B.abcÌefgxyzÌÌ
pinel 2001-12-21
  • 打赏
  • 举报
回复
明白了
加载更多回复(46)

16,551

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧