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

时间:2020-01-01 12:33:21

标签: c++ inheritance design-patterns subclass superclass

我正在尝试实现Flyweight模式,但我不确定继承如何工作,因此我不确定这种模式如何工作。

比方说,我有一个超类,其中包含所有“大量”信息-纹理等内在信息(永不改变的信息)。

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

我的轻量级课程的数据会发生变化:

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

因此,如果我主要创建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?如果是后者,我该如何做,使其仅使用一个实例?

2 个答案:

答案 0 :(得分:1)

您实现的不是轻量级模式。没有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实现来实现。使用其他工厂进行测试等,您可以根据需要切换下面的实现以进行测试。

您的“每个实例”状态不是从Block继承,而是保持独立和按值保留,因为Block实例由BlockFactory拥有,并且仅通过引用传递/指针。

答案 1 :(得分:1)

C ++对象模型可确保子类(即派生的类)的每个实例contains以及其所有超类(即 base 类)的自己的实例)。

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

如果您要共享一个公共状态:

  • 您可以use composition instead of inheritanceBlock_light不会继承自Block,而是引用共享的Block对象。
  • 如果仍然需要互换使用BlockBlock_light,则可以使两者都从一个公共接口(即仅具有虚函数且没有状态的clss)继承{{1} }。
  • 您也可以使用flyweight pattern,其中状态的一部分(共享或不共享)被“外部化”为extrinsinc状态。这种模式的特殊之处在于,调用者将对外部状态的引用提供给类函数,因此,举重对象不需要存储指向这种状态的指针。

第一个选项如下:

IBlock

第二个选项是:

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();
}

我将不介绍flyweight实现的详细信息,但是您有an example here。但是,在选择此模式之前请三思,因为提供共享上下文可能具有挑战性并且容易出错。