为了账号安全,请及时绑定邮箱和手机立即绑定

如何在C ++中使用基类的构造函数和赋值运算符?

如何在C ++中使用基类的构造函数和赋值运算符?

C++
斯蒂芬大帝 2019-11-12 10:16:29
我有一个B带有一组构造函数和一个赋值运算符的类。这里是:class B{ public:  B();  B(const string& s);  B(const B& b) { (*this) = b; }  B& operator=(const B & b); private:  virtual void foo();  // and other private member variables and functions};我想创建一个继承类D,该继承类将覆盖该函数foo(),并且不需要其他更改。但是,我希望D拥有相同的构造函数集,包括复制构造函数和赋值运算符B:D(const D& d) { (*this) = d; }D& operator=(const D& d);我是否必须在中重写所有代码D,还是可以使用B的构造函数和运算符?我尤其要避免重写赋值运算符,因为它必须访问所有B的私有成员变量。
查看完整描述

3 回答

?
郎朗坤

TA贡献1921条经验 获得超9个赞

简短的回答:是的,您将需要在D中重复工作


长答案:


如果派生类“ D”不包含新的成员变量,则默认版本(由编译器生成的版本应该可以正常工作)。默认的Copy构造函数将调用父副本构造函数,默认的赋值运算符将调用父赋值运算符。


但是,如果您的“ D”类包含资源,则您需要做一些工作。


我发现您的副本构造函数有点奇怪:


B(const B& b){(*this) = b;}


D(const D& d){(*this) = d;}

通常,复制构造函数会链接,以便从基础开始进行复制构造。在这里,因为您正在调用赋值运算符,所以复制构造函数必须调用默认构造函数以默认从下至上首先初始化对象。然后,使用赋值运算符再次下移。这似乎效率很低。


现在,如果您执行任务,则是从下至上(或自上而下)进行复制,但是这样做似乎很难,并且要提供强大的异常保证。如果资源在任何时候都无法复制并且引发异常,则对象将处于不确定状态(这是一件坏事)。


正常情况下,我已经看到了相反的情况。

赋值运算符是根据复制构造函数和交换定义的。这是因为它使提供强大的异常保证更加容易。我认为您无法通过这种方式来提供有力的保证(我可能错了)。


class X

{

    // If your class has no resources then use the default version.

    // Dynamically allocated memory is a resource.

    // If any members have a constructor that throws then you will need to

    // write your owen version of these to make it exception safe.



    X(X const& copy)

      // Do most of the work here in the initializer list

    { /* Do some Work Here */}


    X& operator=(X const& copy)

    {

        X tmp(copy);      // All resource all allocation happens here.

                          // If this fails the copy will throw an exception 

                          // and 'this' object is unaffected by the exception.

        swap(tmp);

        return *this;

    }

    // swap is usually trivial to implement

    // and you should easily be able to provide the no-throw guarantee.

    void swap(X& s) throws()

    {

        /* Swap all members */

    }

};

即使从X派生D类,这也不会影响此模式。

诚然,您需要通过对基类进行显式调用来重复一些工作,但这是相对琐碎的。


class D: public X

{


    // Note:

    // If D contains no members and only a new version of foo()

    // Then the default version of these will work fine.


    D(D const& copy)

      :X(copy)  // Chain X's copy constructor

      // Do most of D's work here in the initializer list

    { /* More here */}




    D& operator=(D const& copy)

    {

        D tmp(copy);      // All resource all allocation happens here.

                          // If this fails the copy will throw an exception 

                          // and 'this' object is unaffected by the exception.

        swap(tmp);

        return *this;

    }

    // swap is usually trivial to implement

    // and you should easily be able to provide the no-throw guarantee.

    void swap(D& s) throws()

    {

        X::swap(s); // swap the base class members

        /* Swap all D members */

    }

};


查看完整回答
反对 回复 2019-11-12
?
精慕HU

TA贡献1845条经验 获得超8个赞

您很可能在设计中存在缺陷(提示:切片,实体语义与值语义)。通常根本不需要多态层次结构中的对象具有完整的复制/ 值语义。如果您想提供它,以防万一以后需要它,那意味着您将永远不需要它。而是使基类不可复制(例如,从boost :: noncopyable继承),仅此而已。


当真正出现这种需求时,唯一正确的解决方案是信封字母成语,或者是Sean Parent和Alexander Stepanov IIRC 关于“ 常规对象”的文章中的小框架。所有其他解决方案都会给您带来切片和/或LSP的麻烦。


关于此主题,另请参见C ++ CoreReference C.67:C.67:基类应禁止复制,如果需要“复制”,则应提供虚拟克隆。


查看完整回答
反对 回复 2019-11-12
  • 3 回答
  • 0 关注
  • 474 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信