一个关于多态性的很基本的问题

FredWorks 2004-11-18 06:43:22
我有三个类,他们的关系如下:
class1
{
public: virtual func()=0;
};
class2:public class1
{
public: func()
{
cout<<"class2"<<endl;
}
};
class3:public class1
{
public: func()
{
cout<<"class3"<<endl;
}
}

然后有函数 test:
void test()
{
class1 *c = (class1) new class2;
class3 *d = (class3 *) c;
d->func();
}

结果输出的是:
class2;
为什么输出的不是 class3 呢?
...全文
132 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
勉励前行 2004-11-19
  • 打赏
  • 举报
回复

class1 *c = (class1) new class2;
class3 *d = (class3 *) c; //這句是不合理的。其意思是:把class2的一個實例當做class3來看待
d->func(); //這個func()是2,3共同的父class1所定義的虛函數,其內存定位是由父類定下的,
因為func()是虛函數,是運行期動態綁定的,其函數入口由虛函數表指定,這個虛函數表是每個實例都帶上一個的(不一定是全部,也可能是指針或部分,由編譯器實現),其結果就是由類的實例來指定,生成的是class2的實例,其帶上的就是class2的虛函數表,運行的自然是class的func版本。如果func不是虛函數,那麼就是編譯期靜態綁定,運行的就是class3的func()版本了。

運行期動態綁定的方式,與類的實例相關。
zengwujun 2004-11-19
  • 打赏
  • 举报
回复
new class2得到的是一个类class2的实例
FredWorks 2004-11-18
  • 打赏
  • 举报
回复
不好意思,又打错了,应该是
cat2->sleep();
cat2->walk();
dog2->sleep();
dog2->walk();
FredWorks 2004-11-18
  • 打赏
  • 举报
回复
在楼顶贴初的代码中:
sleep()在Animal中不是虚函数,结果调用的cat->sleep() 显示的是Animal sleep。其中,cat 是被强制转换成的Animal* , 而不是Cat* 类型。这说明cat->sleep()调用的是强制转换后的类型的版本。
而walk()在Animal中是虚函数,结果调用的dog->sleep()显示的结果是 Cat walk(dog对象是通过 Dog *dog = (Dog*) cat; 来获得的). 也就是说,实际调用的是牵制转换前的类型的版本。
但是如果不通过强制类型转换,而是使用动态分配的方式获得Cat 和 Dog 的指针,和上面相同的调用方式却不会出现上面提出的问题(代码如下),为什么会这样?
Cat *cat2 = new Cat;
Dog *dog2 = new Dog;

cat2.sleep();
cat2.walk();
dog2.sleep();
dog2.walk();

此时的输出就是:
Cat sleep
Cat walk
Dog sleep
Dog walk
FredWorks 2004-11-18
  • 打赏
  • 举报
回复
不好意思, Animal 里面的void eat() 函数其实应该是 void sleep();这个函数不是虚函数
FallenAngel 2004-11-18
  • 打赏
  • 举报
回复
你的Animal里面没有定义sleep函数,所以照道理来说,第一个程序的cat->sleep()应该调用出错才对
如果Animal类里面的sleep不是虚函数,那么cat->sleep()显示的是Animal sleep就很正常了,他不是多态,他所调用的就是Animal::sleep,而不是Cat::sleep
FallenAngel 2004-11-18
  • 打赏
  • 举报
回复
你的Animal里面没有定义sleep函数,不过很可能是笔误,那么能告诉我sleep是虚函数嘛?
FredWorks 2004-11-18
  • 打赏
  • 举报
回复
那为什么当不是强制转换而是正常的声明的时候就不会有这种问题呢?比如:
Cat *cat2 = new Cat;
Dog *dog2 = new Dog;

cat2.sleep();
cat2.walk();
dog2.sleep();
dog2.walk();

此时的输出就是:
Cat sleep
Cat walk
Dog sleep
Dog walk
thebigmouse 2004-11-18
  • 打赏
  • 举报
回复
无论你如何转换类的类型,但是虚函数表却不会改变,所以在执行这个虚函数时查到的都是原类型对应的函数入口,而不是转换后的类型的函数入口。
FredWorks 2004-11-18
  • 打赏
  • 举报
回复
为了清晰起见,我把我编译的程序相关的部分贴出来,让前辈们指点

class Animal
{
public:
virtual void walk() = 0;
void eat()
{
cout<<"Animal sleep"<<endl;
}
}

class Cat:public Aninal
{
public:
void walk()
{
cout<<"Cat walk"<<endl;
}
void sleep()
{
cout<<"Cat sleep"<<endl;
}
}
class Dog:public Animal
{
public:
void walk()
{
cout<<"Dog walk"<<endl;
}
void sleep()
{
cout<<"Dog sleep"<<endl;
}
}

void main()
{
Animal *cat = (Animals*)new Cat;
Dog *dog = (Dog*) cat;

cat->walk();
cat->sleep();

cout<<endl;

dog->walk();
dog->sleep();
}

输出结果是:
Cat walk
Animal sleep

Cat walk
Dog sleep

大侠们注意:sleep()在Animal中不是虚函数,结果调用的cat->sleep() 显示的是Animal sleep。注意了,cat 是被强制转换成的Animal* , 而不是Cat* 类型。这说明cat->sleep()调用的是强制转换后的类型的版本。 而walk()在Animal中是虚函数,结果调用的dog->sleep()显示的结果是 Cat walk. 也就是说,实际调用的是牵制转换前的类型的版本。
为什么会这样?
FredWorks 2004-11-18
  • 打赏
  • 举报
回复
在我向来,class3 *d = (class3 *) c;这一句意味着调用的应该是class3的 func()版本,所以输出的应该是class3才正确。但是我编译的结果是class2.
其实我编译的程序中还有一个func1(),它跟func()不同的地方仅仅在于它在class1中不是一个虚函数,而是一个有定义的函数。其他跟func()的情况都一样。但是在test()中调用d->func1();的时候,它的输出结果是class3。
一个在基类中声明了是虚函数,一个没有,其他都是一样的。为什么调用结果不一样呢?
FredWorks 2004-11-18
  • 打赏
  • 举报
回复
to thp(老滕) and h98458(零点起飞):
这个问题其实是我参加腾讯招聘的笔试中遇到的一个问题简化以后得来得,可否讲详细一点?我不太明白。
tanlim 2004-11-18
  • 打赏
  • 举报
回复
其实就是对象指针和对象本身的问题。
对像指针可以指向不同的类尤其经过强制转换后,但对像本身是不变的。不能把对象转变为其他类的对象。
并不涉及多态,
看来是哗众取宠。
windxnet 2004-11-18
  • 打赏
  • 举报
回复
看不出你想做什么。
class3 *d = (class3 *) c;//这个能叫多态吗?

classl *d = new class2;
d->func();

d = new class3;
d->func();
h98458 2004-11-18
  • 打赏
  • 举报
回复
因为class1 *c = (class1) new class2;
所以它调用的是class3的func()版本
thp 2004-11-18
  • 打赏
  • 举报
回复
class2和class3是兄弟关系,不是父子关系。

13,873

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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