【问题标题】:How do I use interfaces in constructors and methods in C++ properly?如何在 C++ 的构造函数和方法中正确使用接口?
【发布时间】:2019-03-31 18:02:55
【问题描述】:

我开始学习 C++ 并且来自 C# 背景,我遇到了很多问题。

我想要做的是尝试使用 C++ 复制我在以下 C# sn-p 中所做的完全相同的事情。这只是 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);
}

【问题讨论】:

  • 如果您刚开始使用 C++,那么最好的做法是尝试忽略您对 C# 的大部分了解,而不是尝试将 C# 代码转换为 C++。首先学习 C++(不要将其与 C# 进行比较和关联),只有在您拥有足够的 C++ 经验和扎实的基础后,您才可以尝试将 C# 程序翻译成 C++。尽管语言结构的语法有相似之处,但两种环境都有很大的不同,因此对于 C++ 初学者来说,尝试将 C# 代码转换为 C++ 代码确实没有多大意义。
  • C# 和 C++ 之间存在一些显着差异,尤其是在这部分。教程很多,一些关键词:继承、虚函数和纯虚函数。如果您使用这些关键字查询 Google,您肯定会找到一些可以解释为什么您的代码无法正常工作的内容。提示:多态性迫使您在几乎所有情况下都使用指针。

标签: c# c++ interface mvp


【解决方案1】:

elgonzo 是对的。你不应该开始通过翻译来学习一门语言,尤其是。介于 C# 和 C++ 之间。它们之间唯一的相似之处是关键字的命名约定。

在这种情况下,重要的区别(除了如何在 C++ 中声明接口)是 C++ 中的所有类型都是按值保存的,而 C# 类是通过引用保存的。您不能使用任何一种语言创建接口的实例(即,您不能在 C# 中执行 new IGameView())。

因此,您的 Game 类型不能按值保存接口类型。它需要是一个指针或引用。这一切都与 C# 非常不同,我建议你按照其他评论者所说的那样,先学习 C++ 基础,然后再回来。

编辑:

这是您发布的 C++ 代码的工作形式。它有 cmets 解释为什么/何时做它的工作。

// 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;
}

【讨论】:

  • 感谢 Cruz Jean 的建议。我实际上正在学习基础知识,同时尝试编写一些我熟悉的代码以进行锻炼。我已经用我的 C++ 实现更新了答案,即使您不同意我的做法,您能否提供一些建议?
  • @Maloooo 好吧,在 C++ 代码中,您正在创建一个接口实例(在 main 中)——您不能这样做。这就像在 C# 中编写 IGameView view = new IGameView() - 不合法。您可能打算在那里创建GameView 的实例。
  • @Maloooo 实际上,我将使用代码和 cmets 来编辑我的答案,解释为什么要在哪里做什么。一秒。
  • 哇,非常感谢!这真的很有帮助!我现在试着把它放回单独的头文件和 cpp 文件中,看看它是怎么回事:)
  • @Maloooo 唯一需要注意的是悬空指针/引用。但是我敢肯定,如果您正在阅读有关 C++ 的书籍/教程,他们会告诉您所有相关信息。祝 C++ 快乐!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
相关资源
最近更新 更多