确定将哪个派生类作为参数传递

时间:2014-10-27 14:49:33

标签: c++ inheritance argument-passing

我正在努力克服我目前的设计并且想知道,如果有可能在不使用铸造方法的情况下决定使用哪种方法。说我有一个基础Fence课程。

此刻,我的工人知道如何建造木栅栏以及如何建造倒钩铁丝网围栏。他们可以在一起添加两个围栏......但到目前为止,他们只学会了如何将木制的木头连接到木制的围栏,以及倒钩的有线围栏和倒钩的围栏。

但是,由于他们可能会了解更多,因此Fence类具有虚拟addFence(const Fence& fence)方法。

由于我想避免任何转换方法,我尝试在两个类中添加特殊的addFence()方法。这是一个例子:

class Fence {
public:
    virtual void addFence(const Fence& fence) = 0;
    ...
};

class BarbWireFence : public Fence {
public:
    ...
    void addFence(const Fence& fence) {
        //only add such a fence, if it is a barb wired one
    }
    void addFence(const BarbWireFence& fence) {
        //continue the fence with the given one
    }
};

class WoodenFence : public Fence {
public:
    ...
    void addFence(const Fence& fence) {
        //only add the fence, if it is a wooden one
    }
    void addFence(const WoodenFence& fence) {
        //continue the fence with the given one
    }
};

现在我想做一些像

这样的事情
Fence *woodenFence1 = new WoodenFence();
Fence *woodenFence2 = new WoodenFence();
woodenFence1->addFence(*woodenFence2);

但由于它是运行时决定我有什么样的围栏,我只有基础Fence*指针,因此在最后一行使用了基础class Fence的定义

那么有更好的实施方案来自动决定吗?我有什么样的围栏?或者我应该使用完全不同的设计?

2 个答案:

答案 0 :(得分:2)

我不知道C ++中的一般方法,但假设你有一组固定的派生类,你可以使用额外的间接来实际处理这种情况:

class BarbWireFence;
class WoodenFence;
class Fence {
public:
    virtual void add(Fence& fence) = 0;
    virtual void add(BarbWireFence& fence) = 0;
    virtual void add(WoodenFence& fence) = 0;
};

class BarbWireFence {
    void add(Fence& fence) override { fence.add(*this); }
    void add(BarbWireFence& fence) override; // deal with the actual addition
    void add(WoodenFence& fence) override;   // deal with the actual addition
};
class WoodenFence {
    void add(Fence& fence) override { fence.add(*this); }
    void add(BarbWireFence& fence) override; // deal with the actual addition
    void add(WoodenFence& fence) override;   // deal with the actual addition
};

答案 1 :(得分:2)

欢迎来到binary methods的精彩世界。

这个问题没有令人满意的解决方案。您可能想了解double dispatch及其更正式的兄弟the Visitor pattern。这两件事情基本相同,只是略有不同。在最简单的场景中,您可以这样做:

class WoodenFence;
class BarbWireFence;

class Fence {
public:
    virtual void addFence(const Fence& fence) = 0;
    virtual void addMe(BarbWireFence& fence) const = 0;
    virtual void addMe(WoodenFence& fence) const = 0;
    ...
};


class BarbWireFence : public Fence {
public:
    ...
    void addFence(const Fence& fence) {
      fence->addMe(*this);
    }
    void addMe(BarbWireFence& fence) const {
      fence->addBarbWireFence(*this);
    }
    void addMe(WoodenFence& fence) const {
      throw error("bad fence combo");
    }

    void addBarbWireFence(const BarbWireFence& fence) {
      // actually add fence...        
    }
};

class WoodenFence : public Fence {
public:
    ...
    void addFence(const Fence& fence) {
      fence->addMe(*this);
    }
    void addMe(BarbWireFence& fence) const {
      throw error("bad fence combo");
    }
    void addMe(WoodenFence& fence) const {
      fence->addWoodenFenceFence(*this);
    }

    void addWoodenFence(const WoodenFence& fence) {
      // actually add fence...        
    }

    ...
};

您可以弄清楚当您添加其他10种围栏类型时会发生什么。

可能会采取完全不同的方向,即对整个业务进行模板化并摆脱Fence基类,因为它没有提供类型安全的接口。

class BarbWireFence {
public:
...
void addSimilarFence(const BarbWireFence& fence) {
    //continue the fence with the given one
    }
};

class WoodenFence {
public:
...
void addSimilarFence(const WoodenFence& fence) {
    //continue the fence with the given one
    }
};

template <typename Fence>
void addFence (Fence& f1, const Fence& f2) {
   f1->addSimilarFence(f2);
}