C++ 从构造函数间接调用纯虚函数是否总是未定义的行为?

C++ 从构造函数间接调用纯虚函数是否总是未定义的行为?,c++,constructor,pure-virtual,C++,Constructor,Pure Virtual,我正在使用xlC编译器构建AIX(请参阅)。Checker类都派生自一个Check类,该类的构造函数在全局列表中注册每个对象: 我似乎遇到的问题是instances().sort()调用sort()将调用Check::operator的确,从构造函数调用纯虚函数始终是一种未定义的行为 在构造函数完全运行(关闭“}”)之前,不能假定设置了虚拟指针,因此对虚拟函数(或纯虚拟函数)的任何调用都必须在编译时设置(静态绑定调用) 现在,如果虚拟函数是纯虚拟函数,编译器通常会为此类纯虚拟函数插入自己的实现,

我正在使用
xlC
编译器构建AIX(请参阅)。Checker类都派生自一个
Check
类,该类的构造函数在全局列表中注册每个对象:


我似乎遇到的问题是
instances().sort()
调用
sort()
将调用
Check::operator的确,从构造函数调用纯虚函数始终是一种未定义的行为

在构造函数完全运行(关闭“}”)之前,不能假定设置了虚拟指针,因此对虚拟函数(或纯虚拟函数)的任何调用都必须在编译时设置(静态绑定调用)

现在,如果虚拟函数是纯虚拟函数,编译器通常会为此类纯虚拟函数插入自己的实现,其默认行为是生成分段错误。标准并没有规定什么是纯虚拟函数的实现,但是大多数C++编译器采用了上述的样式。 如果您的代码没有引起任何运行时恶意行为,那么它就不会在所述调用序列中被调用。如果您可以发布以下2个函数的实现代码

instances().push_back(this);
instances().sort();

然后,也许这会有助于了解发生了什么。

是的,它没有定义。本标准在10.4/6中明确规定了这一点

成员函数可以从抽象类的构造函数(或析构函数)调用;对于从此类构造函数(或析构函数)创建(或销毁)的对象,直接或间接对纯虚拟函数进行虚拟调用(10.3)的效果尚未定义


只要对象构造没有完成,就不能调用纯虚拟函数。但是,如果它在基类a中声明为纯虚拟,然后在B中定义(从a派生),则C的构造函数(从B派生)可以调用它,因为B的构造已经完成

在您的情况下,请改用静态构造函数:

class check {
private Check () { ... }
public:
    static Check* createInstance() {
        Check* check = new Check();
        instances().push_back(check);
        instances().sort();
    }
...
}

我认为您真正的问题在于,您将两件事情混为一谈:Checker基类和一些注册(派生)Check实例的机制

除其他外,这并不特别健壮:我可能希望使用您的Checker类,但我可能希望以不同的方式注册它们

也许您可以这样做:Checker得到一个受保护的ctor(它是抽象的,所以只有派生类应该调用Checker-ctor)

派生类还具有受保护的构造函数和用于创建实例的公共静态方法(“命名构造函数模式”)。该创建方法创建了一个Checker子类,并将其传递(此时完全创建)到CheckerRegister类(该类也是抽象的,因此用户可以在需要时实现自己的类)

您可以使用任何您喜欢的单例模式或依赖项注入机制来实例化Checkerregister并使其可用于Checker子类

一个简单的方法是在Checker上有一个getCheckerRegister静态方法

因此,检查器子类可能如下所示:

类CheckBufferOverflow:公共检查{ 受保护的: CheckBufferOverflow:检查(“边界检查”){ //既然每个派生都有一个名称,为什么不将其作为arg传递呢? } 公众: CheckBufferOverflow MakeCheckBufferOverflow(){ CheckBufferOverflow=新的CheckBufferOverflow()


如果看起来这是一个大量的样板代码,请编写一个模板。如果你担心C++中的每个模板实例都是一个真实的和唯一的类,那么编写一个非模板的基类,它将登记任何一个检查器。

问题链接中的文件名通过GITHUB上的实际完整代码。对不起,我不知道THA。这是一个链接。我正在查看Check.h文件,但我没有看到该头中声明的任何sort()函数。:(对不起,我的错。它是list的函数。没有编译器的行为是“生成分段错误”。这是什么胡说八道?这是我在symbian时代使用ms vc++ide时看到的。另外,要获得更符合逻辑的解释,请参见:这个问题与这个答案并不完全相关,但调用纯虚拟函数会导致seg错误。您无法创建ABC的实例,因此this语句不应甚至编译:Check*Check=new Check();您能详细说明一下吗?我不确定我是否理解您的意思(或者您不理解示例).除此之外,我的代码中还缺少一个冒号。哦,我明白了…您指的是Check类,而不是我给出的示例中的ABC。是的,Check不能实例化-我忽略了Check本身是声明纯虚拟函数的基类。添加一个字符串“name”参数,并让子体在构造时提供一个值。Make
name()
非虚拟并返回构造函数传入的值。此处显示的
检查
构造函数的其余部分可以保持原样。@Rob Kennedy:这是一个很好的解决方案,我将向维护人员建议。是的,并考虑是否值得使用集合而不是实例列表-这可能比ex更快在每次插入后正确调用sort。顺便说一句,您的运算符<将永远不会被sort调用,因为它会比较Check和Check*。是的,Cppcheck中使用的注册机制似乎是为了尽量减少“连接器”的数量代码需要实现一个新的
Check
子类,并让它被主检查循环使用。理论上,只需从
Check
中声明并实现一个派生类,创建一个全局静态实例,程序的其余部分就会开始使用它。我可能不会选择这样做。
instances().push_back(this);
instances().sort();
class check {
private Check () { ... }
public:
    static Check* createInstance() {
        Check* check = new Check();
        instances().push_back(check);
        instances().sort();
    }
...
}
   // get the singleton, pass it something fully constructed
   Checker.getCheckerRegister.register(that) ;
   return that;
}