2

以下代码(来自 C++ FAQs 24.11)正在实现虚拟赋值运算符重载和覆盖:

#include <iostream>
using namespace std;

class B{
public:
    virtual ~B() throw();
    virtual B& operator= (const B& b) throw();
};

B::~B() throw(){}

B& B::operator= (const B& b) throw()
{ cout << "B::operator=(const B&)\n"; return *this; }


class D : public B{
public:
    virtual D& operator= (const B& b) throw();
    D& operator= (const D& d) throw();
};

D& D::operator= (const B& b) throw()
{cout << "D::operator= (const B&)\n"; return *this;}

D& D::operator= (const D& d) throw()
{cout << "D::operator= (const D&)\n"; return *this;}


void sample(D& d, B& b, D& d2, B& b2){
    cout << "d = d2:   "; d = d2;
    cout << "d = b2:   "; d = b2;
    cout << "b = b2:   "; b = b2;
    cout << "b = d2:   "; b = d2;
}


int main()
{
    D d, b, d2, b2;
    sample(d,b,d2,b2);
}

它说输出是:

  • d = d2: D::operator=(const D&)
  • d = b2: D::operator=(const B&)
  • b = b2: D::operator=(const B&)
  • b = d2: D::operator=(const B&)

它说:

“因为编译器会根据参数的静态类型来解析要调用的覆盖,所以第一个赋值是唯一调用接受 D 的赋值运算符的赋值运算符;所有其他最终都调用采用 B 的赋值运算符。”

“最后两个调用解析为覆盖 (D::operator= (const B&)),因为 sample() 中 b 的实际类是 D。如果 b 实际上是 B,最后两个调用将解析为 ( B::operator= (const B&))"

我有点困惑,第一段说编译器查看参数静态类型以确定使用哪个(重载?)函数调用,那么为什么最后一种情况调用 B 参数类型的运算符,当参数传递时, d2,D& d2在 sample() 中被声明为类型?

编辑参考下面的答案,我看不到对 B::=(D) 的请求如何导致 D::=(B)。如果有另一个子类 E 怎么办?为什么会调用 D::=(B) 而不是 E::=(B)?我们是说如果 B 没有参数 (D) 的函数“=”,那么运行时开始查看是否有任何派生对象包含这样的签名?

4

1 回答 1

3

重载解决方案是使用静态类型完成的。一旦选择了重载,动态类型将用于确定使用哪个重写版本的函数。让我解释一下每个结果:

//Every object is a D object, so in
//each case, we expect the virtual calls
//to dispatch to the D version.

//lhs: D, rhs: D, so we expect
//D::operator=(D const&)
cout << "d = d2:   "; d = d2;

//lhs: D, rhs: B, so we expect
//D::operator=(B const&)
cout << "d = b2:   "; d = b2;

//lhs: B, rhs: B, so we expect
//B::operator=(B const&).
//This is virtual, and has been overridden
//in D, so the D version gets called.
cout << "b = b2:   "; b = b2;

//lhs: B, rhs: D, so we expect
//B::operator(D const&).
//This does not exist, so the closest match is used:
//B::operator(B const&). (This is a legal match, 
//because D is a subclass of B).
//This is virtual, and has been overridden
//in D, so the D version gets called.
cout << "b = d2:   "; b = d2;
于 2013-03-02T22:03:39.423 回答