C++ - 派生类 "inherit"的安全/标准方法是来自基类的重载赋值运算符

标签 c++ class inheritance operator-overloading overloading

据我了解,在 C++ 中,派生类不会从基类继承重载的赋值运算符。我在下面编写了一个示例,其中我为基类和派生类显式重载了赋值运算符。在底部的示例输出中,有一个部分:

Index:1 - Base Value:1
Index:1 - Derived Value:2
Index:2 - Base Value:2
Index:2 - Derived Value:2

预期的输出应该是:

Index:1 - Base Value:2
Index:1 - Derived Value:2
Index:2 - Base Value:2
Index:2 - Derived Value:2 

这个输出并不意外。我意识到赋值运算符不是继承的。是否有事实上安全/标准的方法让派生类调用基类的赋值运算符?到目前为止,我最好的猜测是让派生类的赋值运算符函数将派生类对象向上转换为基类对象,并将 RHS 分配给 LHS。这是普遍接受的安全方法吗?

如果我使用“建议的解决方案”(页面底部),它会起作用,但这只是因为没有一个运算符被声明为 virtual。如果我向上转换并使用非虚函数,所使用函数的版本取决于转换,而如果我使用虚函数,所使用的成员函数取决于对象的实际类型而不是它是什么投为。

谢谢。

代码 list


/*******************************************************************************
 * Preprocessor Directives
 ******************************************************************************/
#include <iostream>
using namespace std;


/*******************************************************************************
 * Class Declarations and Function Prototypes
 ******************************************************************************/
class Base {
   private:
   protected:
   public:
      int iBInt;
      Base();        /* Constructor */
      Base(int a);   /* Constructor - Set const member */
      Base & operator=(const Base& rhs);
      virtual ~Base();
};

class Derived : public Base {
   private:
   protected:
   public:
      int iDInt;
      Derived();        /* Constructor */
      Derived(int a);   /* Constructor - Set const member */
      Derived & operator=(const Derived& rhs);
      ~Derived();
};

/*******************************************************************************
 * Class and Function Definitions
 ******************************************************************************/
/******************************************************************************/
Base::Base(void) {
   cout << __FUNCTION__ << endl;
   iBInt = 0;
   cout << "iBInt: " << iBInt << endl;
}

/******************************************************************************/
Base::Base(int a) {
   cout << __FUNCTION__ << endl;
   iBInt = a;
   cout << "iBInt: " << iBInt << endl;
}

/******************************************************************************/
Base::~Base(void) {
   cout << __FUNCTION__ << endl;
}

/******************************************************************************/
Base& Base::operator=(const Base& rhs) {
   cout << "Base::" << __FUNCTION__ << endl;
   if (this == &rhs) {
      return *this;
   }
   iBInt = rhs.iBInt;
   cout << "iBInt: " << iBInt << endl;
   return *this;
}

/******************************************************************************/
Derived::Derived(void) {
   cout << __FUNCTION__ << endl;
   iDInt = 0;
   cout << "iDInt: " << iDInt << endl;
}

/******************************************************************************/
Derived::Derived(int a) : Base(a) {
   cout << __FUNCTION__ << endl;
   iDInt = a;
   cout << "iDInt: " << iDInt << endl;
}

/******************************************************************************/
Derived::~Derived(void) {
   cout << __FUNCTION__ << endl;
}

/******************************************************************************/
Derived& Derived::operator=(const Derived& rhs) {
   cout << "Derived::" << __FUNCTION__ << endl;
   if (this == &rhs) {
      return *this;
   }
   iDInt = rhs.iDInt;
   cout << "iDInt: " << iDInt << endl;
   return *this;
}


/*******************************************************************************
 * Main Entry Point
 ******************************************************************************/
int main(void) {
   int count = 3;
   /* Generate objects */
   Derived **bArr = new Derived*[count];
   for (int i=0; i<count; i++) {
      bArr[i] = new Derived(i);
   }

   /* Set some values via overloaded assignment operator, and print out
    * updated values.
    */
   for (int i=0; i<count; i++) {
      cout << "Index:" << i << " - Base Value:" << bArr[i]->iBInt << endl;
      cout << "Index:" << i << " - Derived Value:" << bArr[i]->iDInt << endl;
   }
   *bArr[1] = *bArr[2];
   for (int i=0; i<count; i++) {
      cout << "Index:" << i << " - Base Value:" << bArr[i]->iBInt << endl;
      cout << "Index:" << i << " - Derived Value:" << bArr[i]->iDInt << endl;
   }
   /* Cleanup */
   for (int i=0; i<count; i++) {
      delete bArr[i];
   }
   delete [] bArr;

   return 0;
}

示例输出


Base
iBInt: 0
Derived
iDInt: 0
Base
iBInt: 1
Derived
iDInt: 1
Base
iBInt: 2
Derived
iDInt: 2
Index:0 - Base Value:0
Index:0 - Derived Value:0
Index:1 - Base Value:1
Index:1 - Derived Value:1
Index:2 - Base Value:2
Index:2 - Derived Value:2
Derived::operator=
iDInt: 2
Index:0 - Base Value:0
Index:0 - Derived Value:0
Index:1 - Base Value:1
Index:1 - Derived Value:2
Index:2 - Base Value:2
Index:2 - Derived Value:2
~Derived
~Base
~Derived
~Base
~Derived
~Base

建议的解决方案/编辑


/******************************************************************************/
Derived& Derived::operator=(const Derived& rhs) {
   cout << "Derived::" << __FUNCTION__ << endl;
   if (this == &rhs) {
      return *this;
   }
   Base* b1 = this;
   Base* b2 = (Base*)&rhs;
   *b1 = *b2;
   iDInt = rhs.iDInt;
   cout << "iDInt: " << iDInt << endl;
   return *this;
}

最佳答案

我会说直接调用 Base 赋值运算符:

Base::operator =(rhs);

以这种方式调用继承类的赋值运算符比用指针体操调用它要干净和直接得多。


另一种方法是:

static_cast<Base &>(*this) = rhs;

这比使用指针调用运算符更干净,但(IMO)仍然不如显式调用基本运算符重载可读。

关于C++ - 派生类 "inherit"的安全/标准方法是来自基类的重载赋值运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25629498/

相关文章:

c++ - 线程和结构通信

java - 使用调用另一个类的 getter 并将该类作为格式化字符串返回?

inheritance - 流 : types inheritance

c++ - 当你是 friend 时,为什么 GCC 不允许从私有(private)嵌套类继承?

java - 为什么我们不能访问java文件中非公共(public)类的方法?

java - 子接口(interface)是默认方法冲突的解决方案吗?

c++ - MySQL/C++ 和准备好的语句 : setInt always 0

c++ - C 和 C++ 之间的字符串字面量差异

c++ - Boost库和最近点

javascript - Electron App - 将主进程分成几个文件并共享变量