虚拟赋值运算符重载 - 如何选择正确的重载函数? [英] Virtual assignment operator overloading- how the correct overloaded function is chosen?

查看:209
本文介绍了虚拟赋值运算符重载 - 如何选择正确的重载函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码(来自C ++常见问题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&)\\\
; 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&)\\\
; return * this;}

D& D :: operator =(const D& d)throw()
{cout< D :: operator =(const D&)\\\
;返回* 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);
}


/ p>


  • d = d2:D :: operator =(const D&)

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

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

  • D :: operator =(const B&)



它说:



< >

因为编译器根据参数的
静态类型解析了覆盖,第一个赋值是唯一一个调用赋值操作符的
, ;所有其他的结束
调用赋值运算符,取一个B.



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


< blockquote>

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



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

解决方案

过载分辨率是使用静态类型完成的。一旦选择了过载,动态类型用于确定使用该函数的哪个覆盖版本。让我解释每个结果:

  //每个对象是一个D对象,因此在
//每个case,我们期望虚拟调用
//调度到D版本。

// lhs:D,rhs:D,所以我们期望
// D :: operator =(D const&)
cout< d = d2:; d = d2;

// lhs:D,rhs:B,所以我们期望
// D :: operator =(B const&)
cout< d = b2:; d = b2;

// lhs:B,rhs:B,所以我们期望
// B :: operator =(B const& amp;)。
//这是虚拟的,并且在D中被重写了
//,所以D版本被调用。
cout<< b = b2:; b = b2;

// lhs:B,rhs:D,所以我们期望
// B :: operator(D const&)。
//这不存在,因此使用最接近的匹配:
// B :: operator(B const&)。 (这是一个法律匹配,
//因为D是B的子类)。
//这是虚拟的,并且在D中被重写了
//,所以D版本被调用。
cout<< b = d2:; b = d2;


The following code (from C++ FAQs 24.11) is implementing virtual assignment operator overloading and overriding:

#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);
}

and it says the output is:

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

It says:

"Because the compiler resolves which override to call based on the static type of the parameters, the first assignment is the only one that calls the assignment operator that takes a D; all the others end up calling the assignment operator that takes a B."

and

"The last two calls resolve to the override (D::operator= (const B&)) because the actual class of b in sample() is D. If b had actually been a B, the last two calls would have resolve to (B::operator= (const B&))"

I'm a bit confused, the first paragraph says the compiler looks at the parameter static type to determine which (overloaded?) function call is used, so why does the last case call the operator for the B parameter type, when the argument passed, d2, is declared as type D& d2 in sample()?

EDIT Referring to the answer below, I do not see how the request for B::=(D) can result in D::=(B). What if there was another subclass, E? Why would D::=(B) get called and not E::=(B)? Are we saying if B does not have a function '=' for parameter (D) then the run-time starts looking at whether any derived objects contain such a signature?

解决方案

Overload resolution is done using the static types. Once the overload is picked, the dynamic type is used to determine which overridden version of the function is used. Let me explain each result:

//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;

这篇关于虚拟赋值运算符重载 - 如何选择正确的重载函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆