为什么继承的protected operator =()具有公共访问权限

时间:2018-03-30 16:32:28

标签: c++

声明为受保护的重载运算符=可以公开访问父类作为公共类的子类。

#include <iostream>

class A {
public:
    A(char c) : i(c) {}
    char i;

protected:
    A& operator=(const A& rdm) {
        std::cout << "accessing operator=()" << std::endl;
        i = 'x';
        return *this;
    }
};

class B : public A {
public:
    B(char c) : A(c) {}
};


int main(int ac, char** av) {

    B a('a');
    B b('b');

    std::cout << "a.i == " << a.i << std::endl;

    a = b;

    std::cout << "a.i == "<< a.i << std::endl;
}

编译时没有错误:

$ g++ -Wall -o test_operator ~/test_operator.cpp
$ ./test_operator
a.i == a
accessing operator=()
a.i == x

使用A直接编译。除operator=()以外的任何其他运算符重载都不会编译。 使用g ++ 4.4.7和7.3.0同时使用c ++ 98和c ++ 17进行测试。

为什么operator=()在这种情况下可以公开访问?

1 个答案:

答案 0 :(得分:6)

B中有隐式副本分配运算符,public访问权限。

来自the C++11 Standard

  

如果类定义没有显式声明一个复制赋值运算符,则会隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认([dcl.fct.def])。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。类X的隐式声明的复制赋值运算符将具有

形式
X& X::operator=(const X&)
     

如果

     

- B的每个直接基类X都有一个复制赋值运算符,其参数类型为const B&const volatile B&B,并且

     

- 对于类X(或其数组)的M的所有非静态数据成员,每个这样的类类型都有一个复制赋值运算符,其参数类型为{ {1}},const M&const volatile M&

     

否则,隐式声明的复制赋值运算符将具有

形式
M

换句话说,您的代码就像您有:

X& X::operator=(X&)

此处的更新版本演示了隐式声明的复制赋值运算符函数的行为。它表明class B : public A { public: B(char c) : A(c) {} B& operator=(B const& rhs) { A::operator==(rhs); return *this; } }; 不会继承B的复制赋值运算符。

A

输出:

#include <iostream>

class A {
public:
    A(char c) : i(c) {}
    char i;

protected:
    A& operator=(const A& rdm) {
        std::cout << "accessing A::operator=()" << std::endl;
        i = 'x';
        return *this;
    }
};

class X
{
   public:
      X& operator=(X const& rhs)
      {
        std::cout << "accessing X::operator=()" << std::endl;
        return *this;
      }
};

class B : public A {
public:
    B(char c) : A(c) {}
    X x;
};


int main(int ac, char** av) {

    B a('a');
    B b('b');

    std::cout << "a.i == " << a.i << std::endl;

    a = b;

    std::cout << "a.i == "<< a.i << std::endl;
}

隐式声明/定义的复制赋值运算符的行为就像我们有:

a.i == a
accessing A::operator=()
accessing X::operator=()
a.i == x

这符合standard says

的内容
  

非联合类B& operator=(B const& rhs) { A::operator==(rhs); this.x = rhs.x; return *this; } 的隐式定义的复制/移动赋值运算符执行其子对象的成员复制/移动分配。 X的直接基类首先按照它们在 base-specifier-list 中声明的顺序分配,然后分配X的直接非静态数据成员。按照在类定义中声明它们的顺序分配。