如何在运行时检查C++抽象方法是否已定义

4
如何在运行时检查C++抽象方法是否已定义
class ABase{
public:
 virtual void do1() = 0;
};

class BBase: public ABase{
public:
 virtual void do1(){}
};

class CBase: public ABase{
public:
};

ABase * base = rand() % 2 ? new BBase() : new CBase();
if(&(base->do1) != 0)
  base->do1();

这会导致错误。

谢谢, Max


1
不需要。那有什么用呢? - Šimon Tóth
1
这里没有虚方法。请看下面我的回答。 - John Dibling
当然会出现错误 - 编译错误。或者缺少 virtual 只是一个错别字或者过去式,你说的是运行时错误吗?还是在那个有趣(而且错误)的比较中出现了编译错误?如果是这样,是哪些错误?这样的问题太草率了,无法得到合理的答案。我投票关闭它,因为它不能被合理地回答。 - sbi
整个代码都是虚假的,它在函数外部声明,并且你不能像 &base->do1 那样获取成员函数的地址,你只能使用 &ABase::do1,但编写代码来尝试做问题所要求的事情的整个前提是错误的。我认为即使答案必须引出问题,这个问题也可以被“回答”。 - CB Bailey
@Max:这仍然没有告诉我们你看到的确切错误,如果是编译时错误,你得到它的哪一行。尽管如此,现在可以做出合理的假设(编译时错误为虚假语法加上误解概念),所以我已经取消了我的负投票。(哦,你应该正确地@地址人在评论回复中,这样你的回复就会显示在他们的响应选项卡中。) - sbi
显示剩余2条评论
7个回答

15

由于无法实例化抽象类,所以在运行时遇到的任何类都不会有任何纯虚方法(除非此时您正在构造函数或析构函数中),它们都已被非纯重写器覆盖。 没有什么需要检查的。


4

为了能够实例化类,必须实现抽象方法。没有检查方法是否已经实现的操作,编译器将自动进行这个过程。在这种情况下,你不能有一个 CBase 对象,因为它具有抽象方法。


3

CBase是抽象类,因为它没有重写ABase::do1()。 因此,您不能实例化它。 或者更确切地说,如果您声明do1()为虚拟函数,就会发生这种情况。但现在它只是无法编译。

不过,知道您为什么要这样做会很好。


我的错误,它是虚拟的。MS VC++编译具有未实现抽象方法的类,并且仅在调用抽象方法时才在运行时引发异常。我猜测对于这样的方法,0被放置在VTABLE中。 - Max

3
编译器不允许您创建一个没有定义所有抽象方法的类型的实例。在您上面的示例中,对 new CBase() 的调用将生成一个编译时错误,类似于“无法实例化抽象类型”。

MS VC++ 进行编译。当我调用这样的方法时,运行时出现异常。(在第一篇帖子中犯了错误,该方法是虚拟的) - Max

1

您不需要在运行时检查方法是否已实现(无论如何,在这种情况下都不能),因为CBase必须实现do1()以满足从ABase继承。


1

假设您记得将do1()函数声明为虚函数,您可以在运行时检查&ABase::do1、&BBase::do1和&CBase::do1。我并不确定比较&ABase::do1和&CBase::do1是否会返回相同的值,仅仅因为CBase没有覆盖该函数,而且只是因为它在一个系统上这样做了,并不能保证在所有系统上都这样。

尽管您可以在运行时测试它们,但如果CBase类不是抽象的,则无法使用这些信息创建该类的对象,因为当它编译失败时,它将无法通过编译。

相反,您可以使用“C”方式:创建一个函数指针表,其中函数指针可以是NULL,检查其中一个是否为NULL,然后创建此实例的结构体或调用它(如果它不是NULL)。


1

您无法实例化CBase,因为它是抽象的,即没有实现其父类的所有纯虚函数。

最简单的方法可能是在ABase中定义一个存根实现:

class ABase {
public:
 void do1() { /* do nothing */ }
};

class BBase: public ABase {
public:
 void do1() { /* do something */ }
};

class CBase: public ABase {};

ABase * base = rand() % 2 ? new BBase() : new CBase();
base->do1();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接