为什么我的赋值运算符没有被调用?

发布于 2024-12-04 04:45:20 字数 496 浏览 0 评论 0原文

我很困惑...为什么我的赋值运算符没有在这里被调用?

template<typename This>
struct mybase
{
    This& operator =(const This &other)
    {
        __debugbreak();  // The debugger should break here, but doesn't.
        return static_cast<This &>(*this):
    }
};

struct myderived : mybase<myderived>
{
    int x;
};

int main()
{
    myderived a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;

    return 0;
}

I'm confused... why isn't my assignment operator getting called here?

template<typename This>
struct mybase
{
    This& operator =(const This &other)
    {
        __debugbreak();  // The debugger should break here, but doesn't.
        return static_cast<This &>(*this):
    }
};

struct myderived : mybase<myderived>
{
    int x;
};

int main()
{
    myderived a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;

    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

冷情 2024-12-11 04:45:20

因为派生中的默认赋值运算符会隐藏基中的重载。

Because the default assignment operator in derived will hide the overloaded in base.

七月上 2024-12-11 04:45:20

mybase::operator= 被自动生成的复制赋值运算符 mydriven::operator= 隐藏。

您可以使用 using 声明使基类运算符在派生类中可见。

编辑:根据请求添加了示例:

template<typename This>
struct mybase
{
    This& operator =(const This &other)
    {
        //__debugbreak();  // The debugger should break here, but doesn't.
        return static_cast<This &>(*this);
    }
};

struct myderived : mybase<myderived>
{
    using mybase<myderived>::operator=;
    int x;
};

int main()
{
    myderived a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;
}

这可以使用 Visual C++ 10.0 和 Comeau Online 进行良好的编译。后者实际上意味着它是良好的标准 C++。但是,该代码无法使用 MinGW g++ 4.4.1 进行编译(编译器错误)。

编辑2:实际上,现在检查,使用 Visual C++ 10.0 它可以编译,但不会调用基类运算符。所以也许 g++ 是正确的。 using 通常是引入基类赋值运算符(或其他)的方法,但在这种情况下,它与派生类的复制赋值运算符具有相同的签名,我还不知道是否Visual C++ 行为正确与否 – 这是该语言的一个极端情况。

编辑3:我检查了N3290(与C++11相同的标准草案),它说

§12.8/18:
如果类定义没有显式声明复制赋值运算符,则隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认(8.4)。

我个人将此解释为,通过使用 using 声明,类“声明”了一个复制赋值运算符,因此不应该隐式生成该运算符(Visual C++ 10.0 似乎是这样做的)。然而,这是该语言的一个极端情况。其他人可能会对此有不同的解释,并且如上所述,编译器有所不同!

干杯&呵呵,,

mybase::operator= is hidden by the automatically generated copy assignment operator myderived::operator=.

You can use a using declaration to make the base class operator visible in the derived class.

EDIT: added example per request:

template<typename This>
struct mybase
{
    This& operator =(const This &other)
    {
        //__debugbreak();  // The debugger should break here, but doesn't.
        return static_cast<This &>(*this);
    }
};

struct myderived : mybase<myderived>
{
    using mybase<myderived>::operator=;
    int x;
};

int main()
{
    myderived a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;
}

This compiles fine with Visual C++ 10.0 and with Comeau Online. The latter means, in practice, that it's good standard C++. However, the code does not compile with MinGW g++ 4.4.1 (compiler bug).

EDIT 2: Actually, checking now, with Visual C++ 10.0 it compiles but the base class operator is not invoked. So maybe g++ is correct. using is generally the way to bring in a base class assignment operator (or whatever), but in this case it has the same signature as the derived class’ copy assignment operator, and I do not yet know whether Visual C++ behavior is correct or not – it is a corner case of the language.

EDIT 3: I checked N3290 (the standard draft that is identical to C++11), and it says

§12.8/18:
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted (8.4).

I personally interpret that as saying that with the using declaration in place the class “declares” a copy assignment operator, and that one should therefore not be implicitly generated (as it seems that Visual C++ 10.0 does). However, this is a corner case of the language. Others may possibly interpret this differently, and as noted above, compilers differ!

Cheers & hth.,

汐鸠 2024-12-11 04:45:20

这行:

a = b;  

显然要求 my衍生 已经重载了复制赋值运算符。它可以由编译器隐式生成,也可以由 mydriven 类显式定义:

12.8 复制类对象 [class.copy]

9. 用户声明的复制赋值运算符 X::operator=
X 的非静态非模板成员函数,恰好为 1
XX&const X&volatile X&const 类型的参数
易失性 X&
.

您尝试在 mybase 类中创建用户声明的复制赋值运算符,但根据 C++ 标准,它实际上并不是复制赋值运算符。想象一下,如果我们用 my衍生This 进行类型替换:

// Hypothetical class generated by the compiler from
// the mybase template class with This = myderived
struct mybase_myderived 
{
    myderived& operator =(const myderived &other) 
    { 
        // ...
    } 
};

显然这不是复制赋值运算符,因为参数 other 的类型是 >const my衍生&,而不是const mybase&。如果 other 参数的类型为 const mybase&mybasemybase&,那么它将是有效的复制赋值运算符,可以由 my衍生 中的默认复制赋值运算符调用。但本例并非如此,因此编译器仍然为 mybase 生成默认的复制赋值运算符,当然在本例中它不执行任何操作。

my衍生 中编译器生成的默认复制赋值运算符调用 mybase 中编译器生成的默认复制赋值运算符。那么最终会发生什么,结果是,operator=(const mydriven &other) 重载永远不会被调用。

编译器不直接调用 mybase::operator= 的原因是因为它被编译器生成的 mydriven 中的复制赋值运算符隐藏了,如 Alf P.斯坦巴赫在这个答案

This line:

a = b;  

obviously requires that myderived have overloaded the copy assignment operator. It can be implicitly generated by the compiler, or defined by the myderived class explicitly:

12.8 Copying class objects [class.copy]

9. A user-declared copy assignment operator X::operator= is a
non-static non-template member function of class X with exactly one
parameter of type X, X&, const X&, volatile X& or const
volatile X&
.

You have attempted to create a user-declared copy assignment operator in your mybase class, but it's not actually a copy assignment operator according to the C++ standard. Imagine if we did a type substitution for This with myderived:

// Hypothetical class generated by the compiler from
// the mybase template class with This = myderived
struct mybase_myderived 
{
    myderived& operator =(const myderived &other) 
    { 
        // ...
    } 
};

Clearly that's not a copy assignment operator, because the parameter other is of type const myderived&, not const mybase&. Had the other parameter be of type const mybase&, or mybase, or mybase&, then it would be a valid copy assignment operator, which can be called by the default copy assignment operator in myderived. But it isn't in this case, so the compiler still generates a default copy assignment operator for mybase, which of course does nothing in this case.

The compiler-generated default copy assignment operator in myderived calls the compiler-generated default copy assignment operator in mybase. So what ends up happening, as As a result, the operator=(const myderived &other) overload is never called.

The reason why the compiler doesn't just call mybase::operator= directly is because it's been hidden by the compiler-generated copy assignment operator in myderived, as Alf P. Steinbach points out in this answer.

小梨窩很甜 2024-12-11 04:45:20

因为编译器在my衍生中引入了默认的赋值运算符。重写它并自己调用您的基本赋值运算符。或者也许 using 指令会有帮助?尝试在 my衍生体中使用 mybase::operator= 。

Because the compiler introduces the default assignment operator in myderived. Override it and call your base assignment operator yourself. Or perhaps a using directive will help? Try using mybase::operator= in myderived body.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文