以下代码(来自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的赋值运算符;所有其他人都结束了 调用带有B的赋值运算符。“
和
“最后两个调用解析为覆盖(D :: operator =(const B&amp;)) 因为sample()中的实际b类是D.如果b实际上是 一个B,最后两个调用将解析为(B :: operator =(const B&安培;))“
我有点困惑,第一段说编译器查看参数静态类型以确定使用哪个(重载?)函数调用,那么为什么最后一种情况会调用B参数类型的运算符,传递的参数d2在sample()中声明为类型D& d2
?
编辑参考下面的答案,我看不出B :: =(D)的请求如何导致D :: =(B)。如果有另一个子类,E怎么办?为什么D :: =(B)被调用而不是E :: =(B)?如果B对参数(D)没有函数'=',那么运行时是否开始查看是否有任何派生对象包含这样的签名?
答案 0 :(得分: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;