Как правильно использовать интерфейсы в конструкторах и методах в C ++? - PullRequest
0 голосов
/ 31 марта 2019

Я начинаю изучать C ++ и пришел из C # фона, у меня много проблем.

То, что я хочу сделать, это попытаться воспроизвести точно то же самое, что я делаю в следующем фрагменте C #, с C ++.Это просто простая реализация шаблона MVP, который я использую довольно часто.

Я пытался разными способами заставить эту работу работать с правильным и современным C ++, но он постоянно дает мне ошибки компиляции, которые я не понимаю должным образом.Большинство из них связано с тем, что я не могу найти правильный способ передачи интерфейса в качестве параметра конструктора, а также для сохранения интерфейса в качестве поля класса.Может ли кто-нибудь перевести этот код C # в правильный код C ++ или хотя бы дать мне совет, пожалуйста?Заранее спасибо.

ПРИМЕЧАНИЕ. Я пытаюсь создать заголовочные файлы только с объявлением классов и cpp-файлами с реальной реализацией.

// This is my C# implementation that I want to convert in C++

public class Program
{
    public static void Main()
    {
        IGameView view = new GameView();
        Game game = new Game(view);
        view.SetPresenter(game);
    }
}

public interface IGameView
{
    void SetPresenter(Game game);
}

public class GameView : IGameView
{
    public void SetPresenter(Game game)
    {
        _game = game;
    }

    Game _game;
}

public class Game
{
    public Game(IGameView view)
    {
        _view = view;
    }

    IGameView _view;
}

Это код C ++, который я пытаюсьсделать компиляцию.Я поместил все здесь без .h и .cpp для ясности и краткости, но, как я уже сказал, я фактически отделяю классы от реализации.

class Game
{
public:
    (IGameView& view) : _view(view)
    { }

    Game operator=(const Game &);

private:
    IGameView& _view;
};

class IGameView
{
public:
    virtual ~IGameView() {}

    virtual void SetPresenter(const Game) = 0;
};

class GameView : public IGameView
{
public:

    GameView();

    void SetPresenter(const Game game) override
    {
        _game = game;
    }

private:
    Game& _game;
};

int main()
{
    IGameView view;
    Game game(view);
    view.SetPresenter(game);
}

1 Ответ

2 голосов
/ 31 марта 2019

Элгонзо прав.Вы не должны начинать изучение языка с помощью переводов, особенноидя между чем-то вроде C # и C ++.Единственное сходство между ними заключается в соглашениях по присвоению имен для ключевых слов.

В этом случае важное отличие (помимо того, как объявлять интерфейсы в C ++) состоит в том, что все типы в C ++ удерживаются по значению, тогда как классы C # удерживаются посредствомссылка.Вы не можете создать экземпляр интерфейса на любом языке (то есть вы не можете сделать new IGameView() в C #).

Таким образом, ваш тип Game не может содержать тип интерфейса по значению.Вместо этого он должен быть указателем или ссылкой.Все это сильно отличается от C #, и я предлагаю вам сделать, как сказали другие комментаторы, и сначала изучить основы C ++, а потом вернуться к этому позже.

Редактировать:

Вот рабочая форма кода C ++, который вы разместили.Там есть комментарии, объясняющие, почему / когда делать то, что он делает.

// C++ requires declaring types before you use them.
// if we want to use Game before defining it we must at least declare that it exists.
class Game;

// this is an interface because it contains abstract (pure virtual) functions.
// you cannot create an instance of an abstract type - but you can make a reference or pointer to one.
struct IGameView
{
    // we might want polymorphic deletion - so to be safe we'll make a virtual dtor.
    virtual ~IGameView() {};

    // Game is probably expensive to copy - pass it by reference.
    // = 0 makes this an abstract method, which makes this an abstract type.
    virtual void SetPresenter(Game &game) = 0;
};

// --------------------------------------------

class Game
{
public:
    // take a reference to the (interface) object to use (we can't pass an abstract type by value)
    Game(IGameView &view) : _view(view) { }

private:
    // hold a reference to the IGameView (interface) object.
    // if you ever wanted this to refer to something else this would need to be pointer instead.
    // references are kind of like pointers that cannot be repointed to something else.
    IGameView &_view;
};

class GameView : public IGameView
{
public:
    GameView();

    virtual void SetPresenter(Game &game) override
    {
        _game = &game;
    }

private:
    // hold a pointer to the Game object.
    // this has to be a pointer because SetPresenter() needs to be able to repoint it (refences can't do that).
    // for safety, initialize this to null.
    Game *_game = nullptr;
};

// ---------------------------------------------

int main()
{
    GameView view; // create the game view to use
    Game game(view); // create the game object and use that view

    view.SetPresenter(game); // set the view to use the game object

    return 0;
}
...