虚拟赋值运算符

3
考虑下面的代码,Calling A应该被打印出来吗?因为a的运行时类型是B,所以虚函数调用应该导致调用B::operator=(因为虚函数调用由左操作数确定)。
#include <iostream>

class A
{
public:
  virtual A& operator=(const A& a_) { std::cout << "Calling A" << std::endl; }
};

class B : public A
{
public:
  virtual B& operator=(const B& b_) { std::cout << "Calling B" << std::endl; }
};

int main() {
  B b1;
  B b2;
  A& a = b1;
  a = b2; // Prints "Calling A", should be "Calling B"?

  return 0;
}

2
没有 A::operator=(const B& b_),只有 A::operator=(const A& a_) - Mohit Jain
1
虚拟赋值是一个不好的想法,因为它将运行时类型检查、移动错误检测等引入了更广泛和不可靠的测试中,从而增加了运行时的负担。 - Cheers and hth. - Alf
如果你想看到 Calling B 消息,你应该在类B中尝试这样做:virtual B& operator=(const A& b_) override { std::cout << "Calling B" << std::endl; return *this; } - αλεχολυτ
当重载operator=时,你也应该总是使用return *this - PC Luddite
@Cheers:您有什么其他建议?在某些情况下,虚拟克隆方法可能足够使用,但并非总是如此。 - MikeMB
@MikeMB:这要看情况。我从来没有需要过,所以很少用到。我想不出有什么情况需要用到它,但如果确实需要,我会认真考虑更改设计,也就是将其视为设计上的问题。 - Cheers and hth. - Alf
6个回答

4

a = b2; 不是虚函数调用。

原因是 B::operator=(const B&) 没有覆盖 A::operator=(const A&),因为它们的签名不同。

您可以使用 override 让编译器自动为您检查这些内容。

使用 override 会做两件事:

  • 防止像这样的简单错误(编译器是您最好的朋友)
  • 使代码更易于理解(“哦,所以这个函数覆盖了某个东西”)

除了编译器优化之外,这不仍然是一个虚函数调用吗?只是一个只能解析为单个虚函数的调用? - MikeMB
1
加上 override,这是它的预期用法。 - henje
1
override 的使用示例? - FreelanceConsultant
2
在基类中:virtual void foo();,在派生类中:void foo() override; - emlai

2
你在B中有一个虚方法 (B::operator=(const B&)),它没有覆盖A中的那个方法 (A::operator=(const A&))。我猜你所写的是一种重载,因此编译器无法知道这样的方法存在,因为你正在使用一个A引用。

2

这个方法:

virtual B& operator=(const B& b_)

不要覆盖这个方法:

virtual A& operator=(const A& a_)

为了覆盖基类的方法,子类必须具有相同的方法签名。
调用 A::operator= 不会将实现委托给派生类,因为派生类没有实现 virtual A& operator=(const A& a_)

0

aclass A 的一个对象,a = b2 将会调用 A& operator=(const A& a_),其中b2的类型将被转换为A类型。测试 b1 = b2 将输出 "Calling B"。

operator= 重载对于每个类来说是唯一的,没有必要将其声明为虚函数。


0

首先,正如其他人已经说过的那样,你的覆盖并没有 - 它只是一个重载。使用 override 关键字来确认这一点。

解决方案是给派生类操作符 完全相同 的签名作为基类的一个,取 A,并在主体中将其 dynamic_cast 到 B。

如果调用者尝试将 A 分配给 B(即,转换失败),则需要考虑要做什么。正如 Alf 在评论中提到的那样,这就是虚拟赋值不太流行的原因。


-1

它只会调用 A::operator= 方法。这是一种方法重载的情况,你无法在两个不同的类中(即使它们继承)实现,因为 C++ 中有名称隐藏特性。


и°ғз”Ёvirtual A& operator=(const A& a_)жҳҜеӣ дёәеңЁеҹәзұ»дёӯжІЎжңүvirtual B& operator=(const B& b_)гҖӮиҝҷдёҚжҳҜеҗҢдёҖдёӘж–№жі•гҖӮ - PC Luddite
但是它们具有相同的签名,就像operator=?函数一样。这些函数具有相同的名称和不同类型的参数。 - MKR Harsha
它们的签名不同。一个是 A& operator=(const A& a_),另一个是 B& operator=(const B&)。这与名称隐藏无关,只是重载。 - PC Luddite
我认为这就是Karthik的意思(这是一种重载而不是覆盖),但并不完全清楚。 - Useless

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接