如果函数是从抽象类派生的,则不能用具体的类指针调用该函数

Not able to call function with concrete class pointer, if it is derived from abstract class

本文关键字:函数 指针 调用 抽象类 派生 如果 不能      更新时间:2023-10-16

我正在使用"g++(Ubuntu/Linaro 4.6.3-1ubuntu5(4.6.3"来运行我的代码。两者都是经过编译的程序。

(1.(
以下程序运行时存在分段故障

#include <iostream>
using namespace std;
class Abstract { 
  public:
    virtual void func() = 0;
};
class A : public Abstract {
  public:
    void func() { cout << "func()" << endl; }
};
int main() {
  A *ao;
  ao->func(); //--> Segmentation fault`<br/>
/*
if we do
A *ao = new A;
ao->func();
then its working
*/
  return 0;
}

当A现在是定义Abstracts方法的具体类时,为什么会观察到这种行为?

(2(如果类不是从抽象类派生的,那么它在这里是有效的。

class A {
  public:
    void func() { cout << "func()" << endl; }
};
int main() {
  A *ao;
  ao->func();
  return 0;
}

使用时,

A *ao;
ao->func(); //--> Segmentation fault

ao未初始化为指向有效对象。在这样的指针上调用成员函数会导致未定义的行为。在您的情况下,这表现为分段错误。

事实上,当没有抽象基类时,它会起作用,这是未定义行为的意外后果,在这种情况下,似乎是理智的行为。

在实际操作中,看似正常的行为是因为您在调用中没有使用A的任何成员变量。在抽象基类的情况下,使用虚拟表。由于指针未初始化为指向有效对象,因此尝试访问虚拟表会导致分段错误。

您有未定义的行为,因为您使用的是未初始化的指针,就好像它被分配了有效对象的地址一样。编译器不会帮你检查——这取决于你把它指向合理的地方。

你所做的有点像把一封信丢在邮箱里,上面没有写地址——谁知道会发生什么?

第一个程序可能会出现分段错误,但第二个程序不会出现,但C++标准并不能保证每次运行程序时都会出现这种错误,更不用说重新编译程序、更改编译器参数、修改代码、尝试其他编译器等了

在实践中,当函数不是虚拟的时,你碰巧"逃脱"它的原因可能是被调用的函数func没有试图通过传递给它的伪this指针访问任何对象数据(它将接受ao的值(:所以指针是垃圾也没关系。当函数为virtual时,它会尝试使用this指针来查找指向虚拟调度表的指针,但随后垃圾指针实际上被卡住,程序崩溃。如上所述,这两种行为都没有得到保证-它是未定义的。

A *ao;
ao->func(); //--> Segmentation fault

ao会有一些垃圾值,当你尝试ao->func((时,你正试图访问ao指向的内存,因为很可能你没有访问权限,所以会出现内存分段错误

A *ao = new A;
ao->func();
then its working

新操作符将为A的实例分配内存,并返回到ao的有效指针,因此它将正常工作。