簡體   English   中英

當您使用庫中的抽象 class 時,如何解決“抽象類的深拷貝”問題?

[英]How do you solve the “deep copy of an abstract class” problem when you are working with an abstract class from a library?

我有一個指向抽象 class 的成員指針,我遇到了一個常見問題,即我無法復制指針指向的內容,因為我不知道指針指向的派生 class 是什么。

在谷歌搜索解決方案時,我發現了這個問題: 復制構造函數:深度復制抽象 class

它提出了這個確切的問題,答案提出了虛擬構造函數習語,其中涉及向抽象基 class 添加一個純虛擬 clone() 方法,然后在所有派生類中覆蓋該方法,以便它們返回分配的指針他們的實際類型。

問題是這個解決方案對我不起作用,因為我需要復制的抽象類型來自庫 (SFML)。 這意味着我無法更改 class 以添加 clone() 方法。

如何在不更改抽象基礎 class 的情況下解決問題?

為了這個答案,假設您正在使用 SFML 的sf::Shape抽象 class:

sf::形狀層次結構

因此,您可能正在通過sf::Shape指針或引用處理sf::CircleShapesf::ConvexShapesf::RectangleShape對象。 這些是具體的類。

您可以定義以下抽象 class ClonableShape ,而不是通過sf::Shape工作:

struct ClonableShape {
    virtual ~ClonableShape() = default;

    virtual std::unique_ptr<ClonableShape> clone() const = 0;

    // extend at will with the member functions from sf::Shape, e.g.:
    virtual const sf::Vector2f& getPosition() const = 0;
    // ...
};

您可以使用此接口通過使用上面的具體類實例化以下 class 模板來多態地克隆這些對象:

template<typename T>
struct Clonable: T, ClonableShape {
    Clonable() = default;

    template<typename... Args>
    Clonable(Args... args): T(args...) {}

    std::unique_ptr<ClonableShape> clone() const override {
        return std::make_unique<Clonable<T>>(*this);
    }

    const sf::Vector2f& getPosition() const override {
        // careful not to call ClonableShape::getPosition() instead
        return T::getPosition();
    }   
};

but you may want to consider composition instead X .也就是說,此解決方案依賴於但您可能需要考慮組合而不是X

最后,您可以多態地克隆形狀對象:

std::unique_ptr<ClonableShape> shapeA(new Clonable<sf::RectangleShape>(sf::Vector2f{4, 4}));
std::unique_ptr<ClonableShape> shapeB = std::make_unique<Clonable<sf::CircleShape>>(4.f);

std::unique_ptr<ClonableShape> shapeC = shapeA->clone();
auto shapeD = shapeB->clone();

由於sf::Shape公開派生自sf::Drawable並且 SFML 庫中有幾個函數接受對sf::Drawable的引用,例如sf::RenderWindow::draw() ,您可能想要擴展ClonableShape上面的接口能夠隱式轉換為sf::Drawable&通過添加:

virtual operator sf::Drawable&() = 0;

然后在Clonable<>中將其覆蓋為:

operator sf::Drawable&() override { return *this; }

這樣,如果你有一個 function 像:

void draw(sf::Drawable&);

您只需編寫以下代碼即可調用它:

draw(*shapeA);

X如果不太依賴具體的類——例如,如果你不直接使用Clonable<sf::RectangleShape>Clonable<sf::CircleShape> ——那么你可能想從inheritance切換到你自己的組合不會過多地取決於通過將具體形狀作為公共基礎繼承的成員函數,而是取決於您在ClonableShape中指定的那些:

template<typename T>
class Clonable: public ClonableShape {
    T shape_; // as data member instead of public base
public:
    Clonable() = default;

    template<typename... Args>
    Clonable(Args... args): shape_(args...) {}

    std::unique_ptr<ClonableShape> clone() const override {
        return std::make_unique<Clonable<T>>(*this);
    }

    const sf::Vector2f& getPosition() const override {
        // careful not to call ClonableShape::getPosition() instead
        return shape_.getPosition();
    }

    // operator sf::Drawable&() override { return shape_; } 
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM