C++ 疑问

发布于 2022-10-15 10:13:49 字数 2229 浏览 75 评论 0

本帖最后由 chenzhanyiczy 于 2011-04-13 17:16 编辑

#include <iostream>
using namespace std;

class base{
  public:   
    virtual ~base(){}
};

class base2{
  public:
    virtual ~base2(){}
};

class derived:public base2,public base{
  public:
     virtual ~derived(){cout<<"this is ~derived"<<endl;}
};

int main(){
   derived dd;
  cout<<"dd's address is :"<<&dd<<endl;                       -->1

   void (*pf)()=(void (*)())*((int*)*(int*)(&dd));
   pf();
}

为什么会有段错误?而去掉1就没有段错误。

先说说个人的看法:段错误当然是访问了不可访问的内存引起的。但就这个例子,就不明白什么情况引起的。
虽然在析构函数中,会默认有个this指针,无论这个this指向哪里,可这个this指向的内容根本没有访问到,
按说不会发生什么段错误,不知道编译器在派生类析构函数中做了什么手脚。回头只能看看汇编了。

另外:

#include <iostream>
using namespace std;

class base{
  public:   
    virtual void foo(){}
};

class base2{
  public:
    virtual void foo2(){}
};

class derived:public base2,public base{
  public:
     virtual void foo(){cout<<"this is foo"<<endl;}
     virtual void foo2(){cout<<"this is foo2"<<endl;}     
};

int main(){
   derived dd;
  cout<<"dd's address is :"<<&dd<<endl;    //                   -->1

   void (*pf)()=(void (*)())*((int*)*(int*)(&dd));
   pf();
}
上面这段代码无论有没有 1 都是没有问题的

编译器是:gcc 4.1.2 20070626

所以问题重点在于编译器对虚析构函数做了什么手脚才会造成段错误的。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

似最初 2022-10-22 10:13:49

本帖最后由 zhujiang73 于 2011-04-13 16:06 编辑

#include
using namespace std;

class base{
  public:   
    virtual ~base(){}
};

class ba ...
chenzhanyiczy 发表于 2011-04-13 15:58

    void (*pf)() 不能用在类内的非静态函数。

千仐 2022-10-22 10:13:49

回复 2# zhujiang73

    对。当然也是可以的。

这里的问题在于:编译器对析构函数做了什么附加动作。而类似*this等动作导致段错误。当然这只是怀疑的情况之一。
不过就这个例子而言,个人觉得编译器不需要对析构函数做什么附加动作,即使做了,也不会出现类似*this等动作。真奇怪。

一瞬间的火花 2022-10-22 10:13:49

回复  zhujiang73

    对。当然也是可以的。

这里的问题在于:编译器对析构函数做了什么附加动作。 ...
chenzhanyiczy 发表于 2011-04-13 16:14

    我认为目前这个 void (*pf)() 里是虚函数表的地址,虚函数表里的内容才是函数的真实地址。

独守阴晴ぅ圆缺 2022-10-22 10:13:49

回复 4# zhujiang73

    void (*pf)()=(void (*)())*((int*)*(int*)(&dd));

pf的值已经是函数的真实地址了,这个可以不用怀疑。仔细看看。
但问题的重点不在于此。

蘸点软妹酱 2022-10-22 10:13:49

不知你用的什么编译器,虚表的第一项不一定是第一个虚函数的指针,也有可能是指向类型信息的指针(就是typeid和dynamic_cast要用到的那个),也有可能是多重继承时用来调整指针的偏移量.

放低过去 2022-10-22 10:13:49

回复  zhujiang73

    void (*pf)()=(void (*)())*((int*)*(int*)(&dd));

pf的值已经是函数的真实 ...
chenzhanyiczy 发表于 2011-04-13 16:28

    这么多括号没看清,不过虚表应该不会这么简单。

浅唱々樱花落 2022-10-22 10:13:49

回复  zhujiang73

    void (*pf)()=(void (*)())*((int*)*(int*)(&dd));

pf的值已经是函数的真实 ...
chenzhanyiczy 发表于 2011-04-13 16:28

    应该是有偏移量,这个在我这可以。 “gcc version 4.5.2 (Debian 4.5.2-

  1. #include <iostream>
  2. typedef int (*PFUN) ();
  3. using namespace std;
  4. class base{
  5.   public:
  6.     virtual ~base(){}
  7. };
  8. class base2{
  9.   public:
  10.     virtual ~base2(){}
  11. };
  12. class derived:public base2,public base{
  13.   public:
  14.      virtual ~derived(){cout<<"this is ~derived"<<endl;}
  15. };
  16. int main()
  17. {
  18.    derived dd;
  19.   cout<<"dd's address is :"<<&dd<<endl;
  20.    PFUN  pf;
  21.    //pf = (PFUN)(&dd);
  22.   int  *p = (int*)(&dd);
  23.   pf = (PFUN)(*(p+2));
  24.    //void (*pf)()=(void (*)())*((int*)*(int*)(&dd));
  25.         std::cout << "pf = " << pf << std::endl;
  26.    pf();
  27. }

复制代码

甲如呢乙后呢 2022-10-22 10:13:49

回复 8# zhujiang73

    这个不行的,段错误的。你确定运行正确?

若水微香 2022-10-22 10:13:49

更新了1楼的描述

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文