题
欲交换功能添加到现有的两个C ++类。一类从另一个继承。我希望每个班实例只交换与同一类的实例。为了让半混凝土,说我有类Foo和Bar。酒吧从富继承。我定义的Foo ::互换(美孚&)和酒吧::互换(酒吧)。酒吧::交换与会代表的Foo ::交换。我想富::交换到富实例和酒吧::交换到酒吧情况下,仅工作唯一的工作:我无法弄清楚如何执行这一要求。
。下面是样本什么给我的麻烦:
#include <algorithm>
#include <iostream>
struct Foo {
int x;
Foo(int x) : x(x) {};
virtual void swap(Foo &other) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
std::swap(this->x, other.x);
};
};
struct Bar : public Foo {
int y;
Bar(int x, int y) : Foo(x), y(y) {};
virtual void swap(Bar &other) {
std::cout << __PRETTY_FUNCTION__ << " ";
Foo::swap(other);
std::swap(this->y, other.y);
};
};
void display(Foo &f1, Foo &f2, Bar &b34, Bar &b56)
{
using namespace std;
cout << "f1: " << f1.x << endl;
cout << "f2: " << f2.x << endl;
cout << "b34: " << b34.x << " " << b34.y << endl;
cout << "b56: " << b56.x << " " << b56.y << endl;
}
int main(int argc, char **argv)
{
{
Foo f1(1), f2(2);
Bar b34(3,4), b56(5,6);
std::cout << std::endl << "Initial values: " << std::endl;
display(f1,f2,b34,b56);
}
{
Foo f1(1), f2(2);
Bar b34(3,4), b56(5,6);
std::cout << std::endl << "After Homogeneous Swap: " << std::endl;
f1.swap(f2); // Desired
b34.swap(b56); // Desired
display(f1,f2,b34,b56);
}
{
Foo f1(1), f2(2);
Bar b34(3,4), b56(5,6);
std::cout << std::endl << "After Heterogeneous Member Swap: " << std::endl;
// b56.swap(f2); // Doesn't compile, excellent
f1.swap(b34); // Want this to not compile, but unsure how
display(f1,f2,b34,b56);
}
return 0;
}
下面是输出:
Initial values:
f1: 1
f2: 2
b34: 3 4
b56: 5 6
After Homogeneous Swap:
virtual void Foo::swap(Foo&)
virtual void Bar::swap(Bar&) virtual void Foo::swap(Foo&)
f1: 2
f2: 1
b34: 5 6
b56: 3 4
After Heterogeneous Member Swap:
virtual void Foo::swap(Foo&)
f1: 3
f2: 2
b34: 1 4
b56: 5 6
可以其中f1.swap(B34)“切片” B34在可能讨厌的方式最终输出组中看到。我想有罪线要么无法编译或运行时炸毁。因为继承的参与,我觉得我碰到了同样的问题,如果我使用一个非成员或朋友交换的实现。
的代码可在键盘是否有帮助。
这个用例的产生是因为我想补充调剂,以提高:: multi_array的和升压:: multi_array_ref的。的multi_array与multi_array_ref继承。它才有意义交换multi_arrays与multi_arrays和multi_array_refs与multi_array_refs。
解决方案
(有点哈克溶液)
添加受保护的虚拟方法,isBaseFoo(),使其在富返回true,并在酒吧假,对于富的交换方法可以检查它的参数有isBaseFoo()==真。
邪恶的,只有在运行时检测到问题,但我想不出什么更好的主意,虽然查尔斯·贝利的回答可能会更好,如果你允许的dynamic_cast <>。
其他提示
交换,像赋值和比较值类型工作得很好,并且不与类层次结构的基础很好地工作。
我总是发现最容易遵循从具体类派生没有,使只有叶类具体的斯科特·梅耶的C ++有效的建议。然后可以安全地实现交换,运算符==,等作为叶节点非虚函数仅
虽然可以有一个虚拟交换功能有虚基类的全部意义就是有动态行为在运行时,所以我认为我对你的失败者试图让所有不正确的可能性在编译时失败。
如果你想要去的虚拟交换路由,那么一个可能的方法是做这样的事情。
class Base
{
public:
virtual void Swap(Base& other) = 0;
};
class ConcreteDerived
{
virtual void Swap(Base& other)
{
// might throw bad_cast, in this case desirable
ConcreteDerived& cother = dynamic_cast<ConcreteDerived&>(other);bad_cast
PrivateSwap(cother);
}
void PrivateSwap(ConcreteDerived& other)
{
// swap implementation
}
};
您不能真正做到这一点,但我不明白这一点,反正。这是不超过切片上operator=
或拷贝构造函数更糟的是,你不能回避后者,无论是。为什么要swap
是任何不同?
由于同样的原因,很可能不值得做<=>虚拟的,出于同样的原因,为什么你不把<=>虚拟的。
我认为,这种情况现在由移动语义的在C ++ 11的存在解决。 我通常使用的交换功能,才避免在作业拷贝复制,所以它仅用于静态,由需要扩展交换功能的派生类和知道的静态类型的基地,所以没有必要为虚拟性(其作为有人说可能会导致细微的问题,切片)。其实我宣布交换功能的保护方法,在我的基地,以确保它不是直接使用其他任何地方。 然后,最具体类可以有最终版本公共如果必要的。
什么你实际上是试图做的是从第三方继承层次的类交换实例。鉴于此,我想关于使用实际类忘记掉,并添加了一个间接层。使用boost :: shared_ptr的是一个好方法;使用含有任何你想要的类shared_ptr实例和交换你的心脏的内容。
在一般情况下,解决问题,你问它在编译时是很难被其他应答者描述的所有原因。