-3

运行此程序时出现“分段错误”。请区分以下两个程序

class xxx{
        public: virtual void f(){cout<<"f in xxx"<<endl;}    //virtual function
                virtual void g(){cout<<"g in xxx"<<endl;}    //virtual function
};
class yyy{           //yyy has no relation with xxx at this context
        public: virtual void f(){cout<<"f in yyy"<<endl;}  //virtual function but no relation with xxx class
                void g(){cout<<"g in yyy"<<endl;}
};
int main(int argc, char *argv[])
{
        xxx x1,*x;
        yyy y1;
        x=&x1;
        x->f();
        x->g();
        x=(xxx*) &y1;        //one class pointer containing another class object address
        x->f();
        x->g();
}

- 输出

f in xxx
g in xxx
f in yyy
Segmentation fault

但是根据多态性概念有同样的问题

class xxx{
        public: virtual void f(){cout<<"f in xxx"<<endl;}     //virtual function
                virtual void g(){cout<<"g in xxx"<<endl;}     //virtual function
};
class yyy:public xxx{             //yyy is derived from xxx
        public: virtual void f(){cout<<"f in yyy"<<endl;}
                void g(){cout<<"g in yyy"<<endl;}
};
int main(int argc, char *argv[])
{
        xxx x1,*x;
        yyy y1;
        x=&x1;
        x->f();
        x->g();
        x=(xxx*) &y1;        //parent class pointer having derived class address
        x->f();
        x->g();
}

- 输出

f in xxx
g in xxx
f in yyy
g in yyy
4

2 回答 2

2

在第一种情况下,强制转换会产生垃圾,因为您告诉编译器好像&y1指向一个xxx而不是指向一个。在第二种情况下, ayyy an xxx,因此将指向 ayyy的指针转换为指向 an 的指针是安全的,xxx因为它一个。

如果您有一个指向卡车的指针,则可以将其视为指向车辆的指针,因为卡车就是车辆。但是,如果您有一个指向花的指针并将其视为指向车辆的指针,则它本质上是一个垃圾指针,并且取消引用它是未定义的行为。

不过,您应该使用 C++ 样式转换而不是 C 样式转换。如果您被迫表达预期的语义,则更有可能发现这种错误。(编写第一个代码的程序员是否认为它可以作为 a 工作static_cast?或者他们是否认为它可以作为 a 工作reinterpret_cast?选择一个代码的额外想法,或者在没有强制转换的情况下执行操作,可能已经避免了错误。)

于 2013-03-14T19:09:30.930 回答
0

在您的第一个示例中:

    x=(xxx*) &y1;        //one class pointer containing another class object address
    x->f();
    x->g();

该变量x实际上指向一个yyy与 class 无关的类xxx。在两者中都声明并且是唯一的虚函数的事实f()使它碰巧起作用。由于g()是类中的虚函数xxx,而不是类中的虚函数yyy,编译器将生成代码来调用虚函数,其中包含一些来自虚函数表(又名)中g()发生的任何垃圾的垃圾[究竟虚函数是如何实现当然是一个实现细节,但可以公平地期望每个类的某处都存储了某种函数“表”]。f()vtable

如果你是这样声明的,它会给你带来更有趣的结果yyy

class yyy{           //yyy has no relation with xxx at this context
        public: virtual void g(){cout<<"g in yyy"<<endl;}  //virtual function but no relation with xxx class
                void f(){cout<<"f in yyy"<<endl;}
};

它会告诉你,作为调用的结果,它必须“g in yyy” f(),然后调用失败g()......因为虚函数的工作方式不是根据它们的名字来调用它们,而是它们的类中的“顺序”[再次,它的工作原理是一个实现细节,由于我们正在处理“未定义的行为”,编译器还可以在屏幕上以闪烁的红色文本打印“答案是 42”或者听起来像紧急呼叫中的救护车——但这比我刚刚在典型的 C++ 编译器实现中描述的更不可能发生]。

在您的第二种情况下,由于virtualofxxx被继承到yyy中,因此该函数g()也是虚拟的yyy,因为“它按您的预期工作”,因为您所做的正是您应该做的。

另请注意,有 C++ 样式转换可帮助您避免犯此类错误 - 如果您做错了,它会在编译 ( static_cast) 时给出错误消息,或者如果您dynamic_cast在编译器无法确定的地方使用type 在编译时,它会给出nullptr结果,这很明显表明你弄错了。

于 2013-03-14T19:19:41.703 回答