在 pimpl 中传递部分构造的对象

Passing the partially constructed object in pimpl

我有一个 class 设置,我已经转换为使用 pimpl,像这样:

(仅提纲,我知道这不会编译)

struct GAME
{
    unique_ptr<GAME_IMPL> _impl; 

    explicit GAME() : _impl( new GAME_IMPL( *this ) );
    IMAGES getImages() { return _impl._images; }
};

struct GAME_IMPL
{
    IMAGES _images;
    PLAYER _player;

    explicit GAME_IMPL( GAME& game ) : _player( game ) { }
};

struct PLAYER
{
    SPRITE _sprite;

    explicit PLAYER( GAME& game ) { _sprite.load( game.getImages() ); }
};

在我转换成粉刺模式之前,这很好。 _sprite.load( game.getImages() ) 可以访问 GAME::_images 因为 GAME::_imagesGAME::_player.

之前实例化

但是转换成pimpl后,可以看到_sprite.load( game.getImages() )会失败——PLAYER无法访问GAME::_images,因为GAME::getImages使用了GAME::_impl,直到 all of GAME_IMPL 构造完成后才分配。

显然我的例子是人为设计的。但是有什么方法可以让 _impl 指针在 GAME_IMPL 对象仍在构造之前或同时被设置?

我考虑了以下几点:

我想你错过了一些细节,这里是编译的设置。

#include <memory>

struct GAME_IMPL;
struct IMAGES {};

// A 'trick' I often use
// for pimpl you can define an abstract base
// helps you check if public and impl class
// implement the same functions
//
// it also ensures you only have a pointer to an interface
// of your implementation in your public header file

struct GAME_ITF
{
    virtual ~GAME_ITF() = default;
    virtual IMAGES get_Images() = 0;
protected:
    GAME_ITF() = default; // prevent accidental instantiation.
};


// in pimpl, game is just forwarding to game_impl
struct GAME : public GAME_ITF
{
    std::unique_ptr<GAME_ITF> _impl;

    GAME();
    virtual ~GAME() = default;

    IMAGES get_Images() override
    {
        return _impl->get_Images();
    }
};

struct SPRITE
{
    void load(IMAGES) { /*..*/ }
};

struct PLAYER
{
    SPRITE _sprite;

    explicit PLAYER(GAME_ITF& game)
    { 
        _sprite.load(game.get_Images());
    }
};

struct GAME_IMPL : public GAME_ITF
{
    IMAGES _images;
    PLAYER _player;

    GAME_IMPL() : 
        _player{*this} // <=== player can refer to the implementation's interface (no impl. details needed either)
    {
    }

    IMAGES get_Images() override
    {
        return IMAGES{};
    }
};

GAME::GAME() :
    _impl(std::make_unique<GAME_IMPL>())
{
}

int main()
{
    GAME game;
    IMAGES images = game.get_Images();
}

P Kramer 的 answer 很好地回答了我的问题。

但是,如果有人通过 Google 单独搜索标题 “通过部分构建的 object”,我确实发现了这个是可能的。本质上,嵌套的 class(本例中为 GAME_IMPL)必须在 parent class(本例中为 GAME)中分配自己的指针,即

explicit GAME_IMPL( GAME& game ) : _player( (game._impl.reset( this ), game) ) { }

现在 GAME::_implPLAYER::PLAYER 期间分配,可以使用 GAME::getImages()

这对于 pimpl 案例来说很麻烦,但可能会解决类似的问题。