【问题标题】:When to use {} () in constructors何时在构造函数中使用 {} ()
【发布时间】:2018-01-29 19:21:27
【问题描述】:

Game.h,我有一个名为Game的类:

class Game
{
public:
    Game();
    void run();
private:
    sf::Event e;
    sf::RenderWindow app;
    sf::Clock delay;
    unsigned counter = 0;
    Ice *ball = new Ice(app);
    Players *players = new Players(app);
    Collision collision;
    void handleEvent();
};

然后,在Game.cpp,我使用:

Game::Game() : app({1000,800},"NAME")
{
}

语法

Game::Game() : app(sf::VideoMode(1000,800),"NAME")
{
}

也可以。

我的问题是:为什么我可以在第一种情况下省略sf::VideoMode,如果我这样做,为什么我必须使用{} 作为视频模式参数?在第一种情况下使用() 会导致错误。

【问题讨论】:

  • 你能发布你的游戏类变量吗?
  • () 根本不应该用于初始化。见list initialization
  • 警告:Ice *ball = new Ice(app);Players *players = new Players(app); Game 不再遵守三法则。这可能会导致一些令人讨厌的错误和丑陋的调试。我建议您熟悉the Rules of 3, 5, and 0,而不是在这里使用动态分配。您可以在成员初始化器列表中将 ballplayers 初始化为普通的旧成员变量,就像使用 app 一样。
  • @user4581301 你能举个例子解释一下为什么不遵守这个规则会导致错误吗?
  • 有很多方法可以意外复制或分配一个类,常见的情况是把它塞进一个标准容器as in this linked answer,然后按值传递。默认行为导致两个对象指向同一个存储。迟早其中一个副本被销毁并释放指针,这使得另一个副本指向无效内存。

标签: c++ syntax constructor sfml


【解决方案1】:

您的Game 构造函数正在调用以下sf::RenderWindow 构造函数:

RenderWindow (VideoMode mode, const String &title, Uint32 style=Style::Default, const ContextSettings &settings=ContextSettings())

您必须向它传递一个完全构造的 sf::VideoMode 对象。

您的两个示例都在 sf::RenderWindow 构造函数调用中内联构造了一个临时 VideoMode 对象。它们都调用了以下sf::VideoMode 构造函数,只是使用了不同的语法:

VideoMode (unsigned int modeWidth, unsigned int modeHeight, unsigned int modeBitsPerPixel=32)

C++11 引入了一个名为“统一初始化”的新特性,它使用花括号将不同上下文中使用的各种不同类型的初始化语法统一为单一语法,从而大大简化了编码。在这种情况下,List Initialization 用于使用braced-init-list 初始化临时对象。正是此功能允许您的 {1000,800} 示例直接在函数参数中构造一个临时的 sf::VideoMode 对象,而无需显式声明其类名。

早期的 C++ 版本没有“统一初始化”。在那些版本中,构造函数只能通过名称显式调用。这就是允许您的 sf::VideoMode(1000,800) 示例构造一个临时的 sf::VideoMode 对象的原因(在 C++11 及更高版本中它仍然是有效的语法)。

(1000,800) 本身在任何 C++ 版本中都不是用于构造对象的有效 C++ 语法。

【讨论】:

    【解决方案2】:

    为什么我可以在第一种情况下省略sf::VideoMode

    因为app 的构造函数的第一个参数已经声明为具有sf::VideoMode 类型。

    这与您可以编写 long v = 1; 而不必编写 long v = long{1}; 或类似的东西的原因相同:编译器知道正在初始化的变量或参数的类型,并且可以检查该类型是否支持使用初始化程序进行构造你指定了,即使初始化器没有相同的类型。

    如果我这样做了,为什么我必须使用{} 作为视频模式参数?

    因为(1000,800) 已经有了不同的更古老的含义:它的意思是“获取值1000,丢弃它,然后获取值800”。诚然,在这种情况下这毫无意义,但没有办法以 (1000,800) 在您的情况下工作的方式重写语言,而同时合理的先前有效代码也继续工作。

    【讨论】:

      猜你喜欢
      • 2018-02-20
      • 2016-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-03
      • 1970-01-01
      相关资源
      最近更新 更多