【问题标题】:Assignment operator inheritance赋值运算符继承
【发布时间】:2012-02-28 00:15:19
【问题描述】:

有这个代码:

#include <iostream>

class Base {
public:
    Base(){
        std::cout << "Constructor base" << std::endl;
    }
    ~Base(){
        std::cout << "Destructor base" << std::endl;
    }
    Base& operator=(const Base& a){
        std::cout << "Assignment base" << std::endl;
    }
};

class Derived : public Base{
public:

};

int main ( int argc, char **argv ) {
    Derived p;
    Derived p2;
    p2 = p;
    return 0;
}

g++ 4.6编译后的输出:

Constructor base
Constructor base
Assignment base
Destructor base
Destructor base

说赋值运算符不被继承,为什么还要调用基类的赋值运算符?

【问题讨论】:

标签: c++ inheritance


【解决方案1】:

其实所谓的就是隐式定义的operator =为Derived。编译器提供的定义依次为Base 调用operator =,您会看到相应的输出。构造函数和析构函数也是如此。当你把它留给编译器定义operator =时,它定义如下:

Derived& operator = (const Derived& rhs)
{
    Base1::operator =(rhs);
    ...
    Basen::operator =(rhs);
    member1 = rhs.member1;
    ...
    membern = rhs.membern; 
}

其中Base1,...,Basen 是类的基类(按照在继承列表中指定它们的顺序),member1, ..., membern 是 Derived 的成员(不包括继承的成员),按照您在类定义。

【讨论】:

  • 最好在该定义中添加return 语句,可能它只是return *this?如果Base1 的操作符不返回对自身的引用,这可能与Base1 的行为不同(但通常就是这种情况)。
【解决方案2】:

你也可以使用“使用”:

class Derived : public Base{
public:
    using Base::operator=;
};

http://en.cppreference.com/w/cpp/language/using_declaration

在有人帮我解决这个问题之前,我已经阅读了好几次这篇文章。

【讨论】:

【解决方案3】:

你没有默认值

Derived& operator=(const Base& a);

在您的 Derived 班级中。

但是,会创建一个默认赋值运算符:

Derived& operator=(const Derived& a);

这会从Base 调用赋值运算符。所以这不是继承赋值运算符的问题,而是通过派生类中默认生成的运算符调用它。

【讨论】:

  • operator= 是从基类继承的,正如我引用 98 c++ 标准“运算符函数的继承方式与其他基类函数相同。”它刚刚被 Derived 类隐式创建的 operator= 隐藏了。
  • "它刚刚被隐式创建的 operator= 为派生类隐藏"。就像基类有 void func(int) 而派生类有 void func(double) 一样,基类函数 void func(int) 是隐藏的。在类似的行中,基类 operator= 被派生类 operator= 隐藏。
  • ...并且要清楚,因为基 operator= 只是被隐藏了,它可以在派生类中取消隐藏 using Base::operator=; 和繁荣:在那里,继承。见:stackoverflow.com/questions/4122214/…
  • @Luchian:如果它没有被继承,则在基类中将其设为私有并查看结果
【解决方案4】:

标准说 (12.8):

赋值运算符应由非静态成员实现 函数只有一个参数。因为复制作业 operator operator= 如果未声明,则为类隐式声明 由用户(12.8),基类赋值运算符始终隐藏 通过派生类的复制赋值运算符。

然后派生的赋值运算符调用你的基础

为非联合隐式定义的复制/移动赋值运算符 X 类对其子对象执行按成员复制/移动分配。 首先分配 X 的直接基类,按照它们的顺序 在基本说明符列表中声明,然后是立即数 X 的非静态数据成员按它们分配的顺序分配 在类定义中声明。

【讨论】:

    【解决方案5】:

    这是因为创建的默认赋值运算符调用它的基本赋值运算符,即它不是继承的,但仍作为默认赋值运算符的一部分调用。

    【讨论】:

    • 赋值运算符是从基类继承的。它只是被派生类中编译器生成的隐藏了。使用using Base::operator=; 将通过取消隐藏基本实现并通过派生类使其可用来证明这一点。见:stackoverflow.com/questions/4122214/…
    【解决方案6】:

    赋值运算符确实不是继承的。继承该运算符将使您能够将Base 分配给Derived,但是Base b; p = a; 将(理所当然地)无法编译。

    编译器会生成一个operator=,因为您还没有为Derived 定义一个自定义的operator=。自动生成的operator= 将调用所有基类和所有成员的赋值运算符。在这方面,它与构造函数/析构函数非常相似,它们也在所有基础/成员上调用相应的函数。

    【讨论】:

    • 赋值运算符是从基类继承的。它只是被派生类中编译器生成的隐藏了。使用using Base::operator=; 将通过取消隐藏基本实现并通过派生类使其可用来证明这一点。见:stackoverflow.com/questions/4122214/…
    猜你喜欢
    • 2021-08-28
    • 2021-06-07
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    • 2020-12-15
    • 2018-11-24
    • 2012-02-12
    • 1970-01-01
    相关资源
    最近更新 更多