论坛首页 编程语言技术论坛

奇怪的方法调用居然可以执行

浏览 4197 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-03-30  
C++
有这样一个类层次结构,Sub1和Sub2是Base的两个子类,在类Sub2中增加一个方法(注意这个方法在Base中和Sub1中都不存在),然后构造Sub1的一个对象,把这个对象的指针转到Sub2类型,调用这个指针的Sub2中新加的方法,居然可以执行

代码如下:
class Base
{
public:
	virtual void processCommon(){}
};

class Sub1: public Base
{
};

class Sub2: public Base
{
public:
	void processOnlyInSub2()
	{
		printf("Sub2.processOnlyInSub2 ...\n");
	}
};

主函数为:
#include "stdafx.h"
#include "base.h"

using namespace std;

int main()
{
	Sub1* sub1Pointer = new Sub1();
	Sub2* sub2Pointer = dynamic_cast<Sub2*>(sub1Pointer);
	sub2Pointer->processOnlyInSub2();
	return 0;
}

因为一直用java而接触C++比较少,所以比较奇怪
   发表时间:2007-03-30  
这样都是可以的

int addr=0x1234;
sub2*p=(sub2*)addr;
p->processOnlyInSub2(); 


再看这里
void processOnlyInSub2()   

这句编译后就是这样子

void processOnlyInSub2(Sub2*this);


而这句
sub2Pointer->processOnlyInSub2();   

相当于  
processOnlyInSub2(sub2Pointer);
0 请登录后投票
   发表时间:2007-03-30  
发现原因了,原来sub2Pointer的值为空也可以调用,不象java那样会抛空指针异常
C++确实没有Java安全和不易出错
0 请登录后投票
   发表时间:2007-03-30  
的确不如Java安全,
不过这个方法跟对象的状态无关,如果访问成员就会异常了。
有一些惯用法是基于这个特性的。

在实践中都是没遇到过因为他不应该正常但却正常了而导致不正常。

0 请登录后投票
   发表时间:2007-03-31  
simohayha 写道
而这句
sub2Pointer->processOnlyInSub2();   

相当于  
processOnlyInSub2(sub2Pointer);

嗯,明白了,感谢指点

我又做了两个实验,一个是定义全局函数void processOnlyInSub2(Sub2*); 结果并没有和类Sub2的调用sub2Pointer->processOnlyInSub2() 产生冲突,所以Sub2的调用虽然编译成processOnlyInSub2(sub2Pointer),但是应该是做了名称(或空间)的特殊除了吧?

第二个是,如果我在父类中也定义一个多态的函数virtual void processOnlyInSub2(),然后子类Sub2再重定义,这样之后象上面那种调用就抛错了
0 请登录后投票
   发表时间:2007-04-04  
关键还是C++中class的实现,所有Class的成员函数隐藏一个参数,也就是this指针,simohayha说得就是这个意思
0 请登录后投票
   发表时间:2007-04-04  
virtual的函数就不一样了,这部分函数是放在vtbl中的,所以需要去找,没有的话就会错误的.
同样你所写的例子,如果函数中用到了class的成员变量也会异常的!
0 请登录后投票
   发表时间:2007-04-04  
qinysong 写道
simohayha 写道
而这句
sub2Pointer->processOnlyInSub2();   

相当于  
processOnlyInSub2(sub2Pointer);

嗯,明白了,感谢指点

我又做了两个实验,一个是定义全局函数void processOnlyInSub2(Sub2*); 结果并没有和类Sub2的调用sub2Pointer->processOnlyInSub2() 产生冲突,所以Sub2的调用虽然编译成processOnlyInSub2(sub2Pointer),但是应该是做了名称(或空间)的特殊除了吧?


严格说,sub2Pointer->processOnlyInSub2();  

并不等于 processOnlyInSub2(sub2Pointer);

C++ 编译器 有 "命名粉碎" 机制,

sub2Pointer->processOnlyInSub2();

大概 产生 类似 于 _ZN4Sub2******(Sub2*) 这样的一个 函数.

嗯,这时候,估计你会想那 弄个 _ZN4Sub2******(Sub2*)这样 名字的函数,看 编译器 怎么办,

编译器 会再次 sub2Pointer->processOnlyInSub2();产生一个其他的名字.

以此类推,总会 产生其他其他的名字.到底 啥 时候 是个头呢, 这要看编译器具体实现了.

记得似乎是 Matthew Wilson 说过, 故意 和 编译器 过不去 会不得好死.

所以别玩的太过火了.
  

0 请登录后投票
   发表时间:2007-04-04  
这个问题在C++圈子论坛里讨论过的,可以去翻翻。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics