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

Igo*_*Oks 92 c++ inheritance constructor assignment-operator

我有一个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
};
Run Code Online (Sandbox Code Playgroud)

我想创建一个D只覆盖函数的继承类,foo()不需要进行其他更改.

但是,我希望D拥有相同的构造函数集,包括复制构造函数和赋值运算符B:

D(const D& d) { (*this) = d; }
D& operator=(const D& d);
Run Code Online (Sandbox Code Playgroud)

我是否必须重写所有这些D,或者有没有办法使用B的构造函数和运算符?我特别想避免重写赋值运算符,因为它必须访问所有B的私有成员变量.

Mot*_*tti 119

您可以显式调用构造函数和赋值运算符:

class Base {
//...
public:
    Base(const Base&) { /*...*/ }
    Base& operator=(const Base&) { /*...*/ }
};

class Derived : public Base
{
    int additional_;
public:
    Derived(const Derived& d)
        : Base(d) // dispatch to base copy constructor
        , additional_(d.additional_)
    {
    }

    Derived& operator=(const Derived& d)
    {
        Base::operator=(d);
        additional_ = d.additional_;
        return *this;
    }
};
Run Code Online (Sandbox Code Playgroud)

有趣的是,即使您没有明确定义这些函数(它然后使用编译器生成的函数),这也可以工作.

class ImplicitBase { 
    int value_; 
    // No operator=() defined
};

class Derived : public ImplicitBase {
    const char* name_;
public:
    Derived& operator=(const Derived& d)
    {
         ImplicitBase::operator=(d); // Call compiler generated operator=
         name_ = strdup(d.name_);
         return *this;
    }
};  
Run Code Online (Sandbox Code Playgroud)

  • @CravingSpirit 它是一个 [复制构造函数](http://en.wikipedia.org/wiki/Copy_constructor)(省略了参数名称)。 (2认同)
  • @CravingSpirit他们在不同的情况下使用,这是基本的C++我建议你多读一点. (2认同)

Mar*_*ork 17

简答:是的,你需要重复D中的工作

答案很长:

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

但是如果你的班级'D'包含资源,那么你需要做一些工作.

我发现你的拷贝构造函数有点奇怪:

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

D(const D& d){(*this) = d;}
Run Code Online (Sandbox Code Playgroud)

通常复制构造函数链,以便它们从基础复制构造.这里因为您正在调用赋值运算符,所以复制构造函数必须调用默认构造函数来默认从底部向上初始化对象.然后使用赋值运算符再次进入.这看起来效率很低.

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

通常我已经看到它反过来做了.
赋值运算符是根据复制构造函数和swap定义的.这是因为它更容易提供强大的异常保证.我认为你不能通过这种方式提供强有力的保证(我可能是错的).

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 */
    }
};
Run Code Online (Sandbox Code Playgroud)

即使您从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 */
    }
};
Run Code Online (Sandbox Code Playgroud)