#include <iostream>
class aa
{
public:
aa(){}
aa(aa& obj)
{
aa1 = obj.aa1;
}
virtual aa operator =(aa& obj)
{
aa1 = obj.aa1;
return (*this);
}
virtual aa operator +(aa& obj)
{
aa1 += obj.aa1;
return (*this);
}
int aa1;
};
class bb: public aa
{
public:
bb():aa(){}
bb(bb& obj)
{
bb1 = obj.bb1;
}
aa operator =(aa& obj)
{
aa::operator =(obj);
bb b1 = dynamic_cast<bb&>(obj);
bb1 = b1.bb1;
return (*this);
}
aa operator +(aa& obj)
{
aa::operator +(obj);
bb b1 = dynamic_cast<bb&>(obj);
bb1 += b1.bb1;
return (*this);
}
int bb1;
};
int main()
{
bb b1;
bb b2;
b1.bb1 = 1;
b1.aa1 = 1;
b2.bb1 = 2;
b2.aa1 = 2;
aa &a1 = b1;
aa &a2 = b2;
a1 = a2;
b1 = dynamic_cast<bb&>(a1);
b2 = dynamic_cast<bb&>(a2);
std::cout<<b1.aa1<<";"<<b1.bb1;
bb b3;
b3.bb1 = 3;
b3.aa1 = 3;
aa &a3 = b3;
aa &a4 = a2 + a3;
b3 = dynamic_cast<bb&>(a4);
return 0;
}
输出: 2;2
,然后将其在崩溃线b3 = dynamic_cast<bb&>(a4);
给错误std::bad_cast at memory location 0x0012fdbc..
我发现原因是A2 + A3的表达的结果来为AA类的对象,并在接下来的发言中,我们试图将它转换为派生类对象,它是无效的,因此导致异常。 所以我的查询就可以实现上述意图,即aa &a4 = a2 + a3;
在上述功能的一些变化?
C ++有一个单一的调度(基于虚拟函数)。 多晶型二元操作不可避免地陷入“双调度”的情况下,并且因此不能由只是简单的虚拟功能的手段polymorphicaly实现。
此外,因为你是返回一个值,每个子类的信息丢失。
处理这种情况更正确的方法是定义一个实现业务和持有多态类型,委托给他们的操作执行的非多态性手柄。
喜欢
class handle
{
public:
class aa;
class bb;
class root
{
public:
virtual ~root() {} //< required being this polymorphic
virtual root* clone()=0;
virtual handle add_invoke(const root& r) const=0; //resolve the 2nd argument
virtual handle add(const aa& a) const=0; //resolve the 1st argument
virtual handle add(const bb& a) const=0; //resolve the 1st argument
};
class aa: public root
{
public:
aa(...) { /*set vith a value */ }
aa(const aa& a) { /* copy */ }
virtual root* clone() { return new aa(*this); }
virtual handle add_invoke(const root& r) const
{ return r.add(*this); } //will call add(const aa&);
virtual handle add(const aa& a) const
{ return handle(new aa(.../*new value for aa with (aa,aa)*/)); }
virtual handle add(const bb& a) const
{ return handle(new bb(.../*new value for bb with(aa,bb)*/)); }
};
class bb: public root
{
public:
bb(...) { /*set vith a value */ }
bb(const bb& b) { /* copy */ }
virtual root* clone() { return new bb(*this); }
virtual handle add_invoke(const root& r) const
{ return r.add(*this); } //will call add(const bb&);
virtual handle add(const aa& a) const
{ return handle(new bb(.../*new value for aa with (bb,aa)*/)); }
virtual handle add(const bb& a) const
{ return handle(new bb(.../*new value for bb with (bb,bb)*/)); }
};
handle() :ps() {}
//support both copy (by clone) and move (by stole)
handle(const handle& s) :ps(s.ps? s.ps->clone(): nullptr) {}
handle(handle&& s) :ps(s.ps) { s.ps=nullptr; };
//assign by value, to force temporary assign
handle& operator=(handle h) { delete ps; ps=h.ps; h.ps=0; return *this; }
//cleanup
~handle() { delete ps; }
//the operator+
friend handle operator+(const handle& a, const handle& b)
{
return (b.ps && a.ps)? b.ps->add_invoke(*a.ps): handle();
//Note: manage also the a+b with one of `a` or `b` as null, if it make sense
}
private:
handle(root* p) :ps(p) {}
root* ps;
};
字面上重载aa operator +(aa& obj)
在派生类没有什么意义。
即使当虚拟现在你会调用返回的方法aa
在任何时间,所以结果a2 + a3
将是aa
的对象,从来没有一个BB的对象。 它被构造为bb
对象,但复制到所产生的aa
对象,副本失去bb
信息。
你应该做的是替代特定版本的bb operator +(const bb& obj)
注意,然而,这将隐藏原始operator+
为aa
论据,你仍然有重新定义它或进口的using
语句 。
现在,这些是更好的语义,但它不会解决你的问题,因为在你的情况下,它仍然会调用operator+
返回一个aa
对象。 在这种情况下,如果你真的想解决这个问题,你应该下来投a2
和a3
将在他们面前 。
但实际上,如果你在虚拟化功能的父子系统做这样的事情,你可能会重新考虑你的设计。 通常情况下,使用的dynamic_cast
应该提高在任何情况下,一些人感到惊讶。 这当然有它的用途,但再次向下转换应避免尽可能。
你传递一个基类,它为什么会转换为派生投? 你应该抓住从铸造例外,因为这是你如何知道类型是不是你所期望的。
需要注意的是,虽然a1
和a2
都参考的情况下bb
, a4
是没有的。 这就是为什么前两个类型转换没有抛出异常。