C ++ 11委托构造函数纯虚拟方法&函数调用 - 危险? [英] C++ 11 Delegated Constructor Pure Virtual Method & Function Calls -- Dangers?

查看:179
本文介绍了C ++ 11委托构造函数纯虚拟方法&函数调用 - 危险?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

不是重复的调用虚拟函数和纯虚函数



前问题涉及C ++ 03,而不是C ++中的新构造函数委托



在C ++ 11中,我们可以通过使用代理来确保在执行纯虚拟实现之前的正确构造。在构造函数中调用Pure Virtual函数的危险是什么,在构造函数中,但是在通过构造函数委托完成了完全构造之后?



,成员函数(包括虚函数成员函数,10.3)可以是
()函数,其中的成员函数可以是:



$ b呼吁正在建设的对象。类似地,
构造下的对象可以是typeid运算符的操作数。
- 12.6.2 [C ++工作草案]的第13条( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
无法找到已发布规格的合理使用版本。



C ++ 11考虑一旦任何构造函数完成
执行。由于多个构造函数将被允许执行,
这意味着每个委托构造函数将在一个
完全构造的自己类型的对象上执行。派生类构造函数
将在其基类中的所有委派完成后执行。
- 维基百科说这是一个C ++ 11的东西。




实际的C ++ 11参考未知。



下面的示例编译和联合Visual Studio 2012 C ++ 11 CTP编译器:

  #include< string& 

/ ************************************** /
class Base
{
public:
int sum;
virtual int Do()= 0;

void Initialize()
{
Do();
}
Base()
{
}
};

/ ************************************** /
//可选地将类声明为final,以避免
//进一步子派生的问题。
class Derived final:public Base
{
public:

virtual int Do()override final
{
sum = 0? 1:sum;
return sum / 2; // .5如果尚未设置。
}

Derived(const std :: string& test)
:Derived()//确保构造了this对象。
{
Initialize(); //调用纯虚方法。
}
Derived()
:Base()
{
//有效地实例化基类。
// Then instantiating This。
//目标构造函数完成。
}
};




/ *************************** *************************************** /
int main(int args, char * argv [])
{
Derived d;
return 0;
}


解决方案

代码看起来不错,注意,如果你有一个子类的Derived,子类的重写Do()不会被Derived(const std :: string&)调用,而是Derived :: Do()仍然会被调用;这可能不是你想要的。特别是,当从Derived(const std :: string&)构造函数调用Initialize()时,对象仍然是只有一个Derived对象而不是一个SubDerived对象(因为SubDerived层的构造代码hasn' t开始),这就是为什么Derived :: Do()将被调用而不是SubDerived :: Do()。



问:如果子类使用相同代理模式,以确保一切都以同样的方式实例化?



A:这将主要工作,但只有当它是好的Derived :: Do() SubDerived :: Do()被调用。



特别是,你有类SubDerived,做与Derived相同的事情。然后当调用代码这样做:

  SubDerived foo(Hello); 

会发生以下顺序的调用:

  Base()
Derived()
Derived(const std :: string&)
Base :: Initialize :: Do()
SubDerived()
SubDerived(const std :: string&)
Base :: Initialize()
SubDerived :: Do()

...因此,SubDerived :: Do()最终会被调用,但Derived :: Do也被称为。是否这将是一个问题取决于各种Do()方法实际做什么。



一些建议:从构造函数中调用虚拟方法通常不是最好的方式去。您可能需要考虑简单地要求调用代码在对象构造之后手动调用Do()。这对于调用代码有一点工作,但是它的优点是它可以避免在对部分构造的对象进行虚拟方法调用时出现的非常明显或者方便的语义。


Not a Duplicate of Invoking virtual function and pure-virtual function from a constructor:

Former Question relates to C++ 03, not new Constructor Delegation behavior in C++ 11, and the question does not address the mitigation of undefined behavior by using delegation to ensure proper construction before pure virtual implementations are executed.

In C++ 11, what are the dangers of invoking Pure Virtual functions in a class' constructor, during construction, but after the class/object has been "fully constructed" via constructor delegation?

Apparently, somewhere in the C++ 11 spec such a constraint exists,

Member functions (including virtual member functions, 10.3) can be called for an object under construction. Similarly, an object under construction can be the operand of the typeid operator .. - 12.6.2 #13 of the [C++ Working Draft] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf) Can't find "Fair Use" version of Published Spec.

C++11 considers an object constructed once any constructor finishes execution. Since multiple constructors will be allowed to execute, this will mean that each delegate constructor will be executing on a fully constructed object of its own type. Derived class constructors will execute after all delegation in their base classes is complete. - Wikipedia saying that this is a C++ 11 thing.

Actual C++ 11 Reference unknown.

Following Example Compiles AND RUNS in Nov CTP of Visual Studio 2012 C++ Compiler:

#include <string>

/**************************************/
class Base
{
public:
    int sum;
    virtual int Do() = 0;

    void Initialize()
    {
        Do();
    }
    Base()
    {
    }
};

/**************************************/
// Optionally declare class as "final" to avoid
// issues with further sub-derivations.
class Derived final : public Base
{
public:

    virtual int Do() override final
    {
        sum = 0 ? 1 : sum;
        return sum / 2 ; // .5 if not already set.
    }

    Derived(const std::string & test)
        : Derived() // Ensure "this" object is constructed.
    {
        Initialize(); // Call Pure Virtual Method.
    }
    Derived()
        : Base()
    {
        // Effectively Instantiating the Base Class.
        // Then Instantiating This.
        // The the target constructor completes.
    }
};




/********************************************************************/
int main(int args, char* argv[])
{
    Derived d;
    return 0;
}

解决方案

With the updates, the example code looks okay to me, with the caveat that if you ever make a subclass of Derived, the subclass's override of Do() won't get called by Derived(const std::string &), rather Derived::Do() will still get called; which might not be what you wanted. In particular, when Initialize() is called from the Derived(const std::string &) constructor, the object is still "only" a Derived object and not a SubDerived object yet (because the SubDerived layer of construction-code hasn't started yet) and that is why Derived::Do() would be called and not SubDerived::Do().

Q: What if the subclass uses the same delegation pattern to ensure everything is instantiate in the same way?

A: That would mostly work, but only if it's okay for Derived::Do() to be called before SubDerived::Do() is called.

In particular, say you had class SubDerived that did the same things as Derived does above. Then when the calling code did this:

SubDerived foo("Hello");

the following sequence of calls would occur:

Base()
Derived()
Derived(const std::string &)
  Base::Initialize()
    Derived::Do()
SubDerived()
SubDerived(const std::string &)
  Base::Initialize()
    SubDerived::Do()

... so yes, SubDerived::Do() would eventually get called, but Derived::Do() would have been called also. Whether or not that will be a problem depends on what the various Do() methods actually do.

Some advice: Calling virtual methods from within a constructor is usually not the best way to go. You might want to consider simply requiring the calling code to call Do() manually on the object after the object is constructed. It's a bit more work for the calling code, but the advantage is that it you can avoid the not-very-obvious-or-convenient semantics that come into play when doing virtual method calls on partially-constructed objects.

这篇关于C ++ 11委托构造函数纯虚拟方法&amp;函数调用 - 危险?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆