继承场景中的C++交换问题

Rhy*_*ich 3 c++ swap boost

我想将交换功能添加到两个现有的C++类中.一个类继承自另一个类.我希望每个类的实例只能与同一个类的实例交换.为了使它成为半混凝土,说我有Foo和Bar课程.Bar继承自Foo.我定义了Foo :: swap(Foo&)和Bar :: swap(Bar&).Bar :: swap委托给Foo :: swap.我希望Foo :: swap只能在Foo实例上工作而Bar :: swap只能在Bar实例上工作:我无法弄清楚如何强制执行此要求.

这是给我带来麻烦的一个例子:

#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;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

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
Run Code Online (Sandbox Code Playgroud)

您可以在最终输出组中看到f1.swap(b34)以可能令人讨厌的方式"切片"b34.我不喜欢在运行时编译或爆炸的罪行.由于涉及到继承,我认为如果我使用非成员或朋友交换实现,我会遇到同样的问题.

如果有帮助,代码可以在键盘上找到.

这个用例的出现是因为我想将swap添加到boost :: multi_array和boost :: multi_array_ref.multi_array继承自multi_array_ref.将multi_arrays与multi_arrays和multi_array_refs与multi_array_refs交换是有意义的.

CB *_*ley 5

交换,就像赋值和比较一样,可以很好地处理值类型,并且不适用于类层次结构的基础.

我总是发现最容易遵循Scott Meyer的Effective C++建议,即不从具体类派生,只使叶子类具体化.然后,您可以安全地将swap,operator ==等实现为仅用于叶节点的非虚函数.

虽然可以使用虚拟交换函数,但是拥有虚拟基类的重点是在运行时具有动态行为,因此我认为您正试图在编译时尝试使所有不正确的可能性失败.

如果你想进入虚拟交换路由,那么一种可能的方法就是做这样的事情.

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
    }
};
Run Code Online (Sandbox Code Playgroud)