2012-01-15 61 views
3

我想了解这种行为,但似乎我没有。请参阅此代码:派生类是否间接继承了基的赋值运算符?

#include <iostream> 
using namespace std; 

class Base 
{ 
public: 
    void operator=(const Base& rf) 
    { 
     cout << "base operator=" << endl; 
     this->y = rf.y; 
    } 
    int y; 
    Base() : y(100) { } 
}; 

class Derived : public Base 
{ 
public: 
    int x; 
    Derived() : x(100) { } 
}; 

int main() 
{ 
    Derived test; 
    Derived test2; 
    test2.x = 0; 
    test2.y = 0; 
    test.operator=(test2); // operator auto-generated for derived class but... 
    cout << test.x << endl << test.y << endl; 
    cin.ignore(); 
    return 0; 
} 

程序输出:

> base operator= 
> 0 
> 0 

现在在那里我感到困惑的是: 规则说,一个派生类中从未继承分配新建分配FY操作,而是创建了自己的operator=然而在这个例子中,基类的operator=被派生类调用。

其次,我能够明确地调用分配新建分配FY运营商在派生类中,这是不是又在派生类中明确定义。

现在,如果我理解正确的话,这意味着任何用户定义的基本的操作总是被在派生类中调用?

回答

12

自动生成的调用基类赋值运算符。

// generated version looks basically like this 
Derived& operator=(Derived const& other){ 
    Base::operator=(static_cast<Base const&>(other)); 
    x = other.x; 
    return *this; 
} 

演员阵容有避免模板化Base::operator=一个的意外电话像这样的:

template<class Other> 
Base& operator=(Other const& other); // accepts everything 

还是一个陌生的一个是这样的:

// forward-declare 'Derived' outside of 'Base' 
Base& operator=(Derived const& other); // accepts derived class (for whatever reason) 

其次,我能够明确地在派生上调用分配操作符d类,它不会在派生类中明确定义。

编译器会自动声明赋值运算符,如果你不这样做,你的类允许它(即无参考成员和其他一些晦涩难懂的规则),另外定义它,如果你真正使用它的地方。

4

的编译器生成的赋值运算符调用每个子对象的赋值运算符。这包括基类和非静态成员变量。

的标准说(12.8节[class.copy]):

如果该类德网络nition没有显式声明的拷贝赋值运算符,一个是隐式声明。如果类定义声明移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为删除;否则,它被定义为默认(8.4)。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用后一种情况。一类X的隐式声明的拷贝赋值运算符将有

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

如果

  • 每个直接基类的XB有拷贝赋值运算符,其参数为const B&型的形式, const volatile B&B
  • 对于类型为M(或数组的所有非静态数据成员X物),每个这样的类型具有拷贝赋值运算符,其参数是const M&类型,const volatile M&M的。

否则,隐式声明的拷贝赋值运算符将有形式

X& X::operator=(X&) 

的非工会类隐式定义的复制/移动赋值运算符X执行其子对象的成员复制/移动分配。的X直接基类是第一分配,在其声明的顺序在基本符列表,再X眼前的非静态数据成员分配,在他们在声明的顺序类定义。假设x是函数 的参数,或者对于移动运算符,是指参数的xvalue。每个子对象以适合其种类的方式分配:

  • 如果子对象是类的类型,仿佛通过向operator=一个呼叫与所述子对象为对象的表达和x作为单个功能的相应子对象(如同通过明确的限定;即忽略更多派生类中的任何可能的虚拟重写函数);
  • 如果子对象是一个数组,每个元素都以适合元素类型的方式分配;
  • 如果子对象是标量类型,则使用内置赋值运算符。

未明确表示虚拟基类的子对象是否由隐式定义的复制赋值运算符多次分配。

+0

这是否意味着用户定义的运算符不会调用子对象的运算符?你是说只有编译器生成的操作符调用的子对象的操作符? – codekiddy 2012-01-15 04:18:18

+1

@codekiddy:除非你自己调用基类版本,否则编译器不会为你做。 – Xeo 2012-01-15 04:19:06

+0

非常感谢你! – codekiddy 2012-01-15 13:03:28

2

这是因为隐含定义的operator =调用基类operator =。请参见常见问题解答精简版:

I'm creating a derived class; should my assignment operator call my base class's assignment operator?

是(如果你需要定义首先赋值运算符)。

如果您定义了自己的赋值运算符,那么编译器不会自动为您调用基类的赋值运算符。除非基类的赋值操作符本身被破坏,否则应该从派生类的赋值操作符中明确调用它(同样,假设您首先创建一个)。

但是,如果您不创建自己的赋值运算符,那么编译器为您创建的赋值运算符将自动调用您的基类的赋值运算符。

+0

谢谢,这是非常有用的! – codekiddy 2012-01-15 13:29:34

-1

4事情永远不会继承 构造 拷贝构造 赋值运算符 析构函数

即使你没有写赋值运算符你的代码将是沃金罚款。 无论何时使用赋值运算符,编译器都会确保调用每个成员对象和基类的赋值运算符。

+0

这只是不正确的,请参阅我的答案下面的评论。 – 2012-01-15 16:13:28

+0

@本 - 可能是我没有说明整个事情;我在谈论编译器提供的功能。 – Amit 2012-01-15 20:12:17

相关问题