虚拟赋值运算符

时间:2015-07-15 07:06:32

标签: c++

根据下面的代码,不应该打印Calling B,而不是Calling A?不是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;
}

5 个答案:

答案 0 :(得分:3)

a = b2; 虚拟来电。

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

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

使用override会做两件事:

  • 可以防止像这样的简单错误(编译器是你最好的朋友)
  • 使代码更容易理解(&#34;哦,所以这个函数覆盖了某些内容&#34;)

答案 1 :(得分:2)

此方法:

mouseMove

不会覆盖此方法:

virtual B& operator=(const B& b_)

为了覆盖基类的方法,子进程必须具有相同的方法签名。

调用virtual A& operator=(const A& a_) 不会将实现推迟到派生类,因为派生类没有A::operator=的实现。

答案 2 :(得分:0)

aclass A的对象,原因a = b2会调用A& operator=(const A& a_)b2的类型将转换为A类型。测试b1 = b2将输出“呼叫B”。

operator=覆盖对于每个类都是唯一的。没有必要将它声明为虚函数。

答案 3 :(得分:0)

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

解决方案是为派生类运算符提供与基类1完全相同的签名,将A和dynamic_cast转换为正文中的B.

如果调用者尝试将A分配给B(即,转换失败),您需要考虑该怎么做。正如Alf在评论中提到的,这就是虚拟作业不受欢迎的原因。

答案 4 :(得分:-1)

它只会调用A :: operator =。 。由于c ++中的名称隐藏功能,它是方法重载方案,你无法在两个不同的类中实现(即使它是继承的)。