创建一个子类的多个实例,只有一个超类的实例

Creating multiple instances of a subclass, with only one instance of a superclass

我正在尝试实现享元模式,但我不太确定继承是如何工作的,所以我不太确定这种模式是如何工作的。

假设我有一个超级class,它包含所有 "heavy" 信息——纹理等,内在信息(永远不会改变的信息)。

class Block{
public: //for the sake of the example
Texture tex; 
etc.
};

我的灯 class 的数据会发生变化:

class Block_light : public Block {
public:
int posX, posY, posZ;
int color;
etc.
};

那么,如果我在 main 中创建 n Block_light,我会同时创建 n Block 还是它们都将绑定到一个实例?

 int main(){
 std::vector<Block_light> blocks(n);
 return 0;
 };

我创建了 n Block_light 和 1 Block 还是 n Block_light 和 n Block?如果是后者,我怎样才能让它只使用一个实例?

您实现的不是轻量级模式。没有 Block_light 这样的东西,而 Block 将是一个纯接口,可以实现由 Block1 之类的东西提供的实现,它看起来像你的 Block 定义的样子。

例如:

#include <string>
#include <unordered_map>
#include <memory>

class BlockState {
public:
    int posX, posY, posZ;
    int color;
};

struct Texture {
    Texture(const std::string &);
    char data[8196];
};

class Block {
public:
    Block(std::string) {};
    virtual void render(const BlockState &state) const = 0;
};

class Block1 final : public Block {
public:
    Block1(std::string name) : Block(name), tex(name) {};
    void render(const BlockState &state) const override;
private:
    const Texture tex;
};

class BlockFactory final {
public:
    std::shared_ptr<const Block> getBlock(const std::string &key) {
        auto it = dict.find(key);
        if(it != dict.end()) return it->second;
        auto it2 = dict.try_emplace(key, std::make_shared<Block1>(key));
        return it2.first->second;
    }
private:
    std::unordered_map<std::string, std::shared_ptr<const Block>> dict;
};

void render () {
    static BlockFactory factory;
    BlockState a, b;
    factory.getBlock("brick")->render(a);
    factory.getBlock("brick")->render(b);
}

BlockFactory 正在为您管理 Block 的实例,由不可见的 Block1 实现实现。使用不同的工厂进行测试等,您可以根据需要切换下面的实现来进行测试。

您的 "per instance" 状态不是从 Block 继承的,而是按值保持独立的,而 Block 实例由 BlockFactory 拥有且仅通过引用/指针传递。

C++ 对象模型确保每个子实例class(即派生class)contains也是它自己的实例它的所有超级classes(即base classes)。

在您的情况下,这意味着每个 Block_light 对象都将具有所有 Block_light 属性,以及具有所有 BlockBlock 子对象特性。换句话说,Block_light一点都不轻

如果你想分享一个共同的状态:

  • 您可以 use composition instead of inheritanceBlock_light 不会继承自 Block,而是引用一个共享的 Block 对象。
  • 如果您仍然需要能够互换使用 BlockBlock_light,您可以使两者都继承自一个公共接口(即只有虚函数而没有状态的 clss)IBlock.
  • 您也可以使用 flyweight pattern,其中部分状态(共享或非共享)被“外部化”为外部状态。这种模式的特殊性在于,外部状态的引用由调用者提供给classes函数,因此享元对象不需要存储指向这种状态的指针。

第一个选项如下所示:

class Block {...}; 
class Block_light {       // no inheritance 
    shared_ptr<Block> b;  // but (private) composition   
    ...
};  

第二个选项是:

class IBlock {  // no member variables
public:
    virtual Texture get_texture()=0;
    virtual ~IBlock(){}; 
};  

class Block : public IBlock {  // sharable state
    Texture tex; 
public: 
    Texture get_texture() override { return tex; }
};    

class Block_light : public IBlock {
    shared_ptr<IBlock> b;  // or IBlock or Block depending on the needs.  
public:
    Block_light (shared_ptr<IBlock>i) : b(i) {}
    Texture get_texture() override { return b->get_texture(); }
};  

int main() { // just a perfectible quick example
    auto myb=make_shared<Block>();
    Block_light b1(myb);
    b1.get_texture();
}

最后一个会这样使用:

int main() { // just a perfectible quick example
    Block myb;     // shared part; 
    Block_light bl;
    bl.get_texture(myb);
}

我不会进入享元实现的细节,但你有 an example here。但是,在选择此模式之前请三思,因为提供共享上下文可能具有挑战性且容易出错。