默认构造函数的奇怪错误(C++)

Posted

技术标签:

【中文标题】默认构造函数的奇怪错误(C++)【英文标题】:Strange bug with default constructor (C++) 【发布时间】:2013-02-20 12:52:34 【问题描述】:

首先,如果答案很明显,我想提前道歉;我对 C++ 很陌生,我的第一语言是 Java。我也是 Stack Overflow 的新手,所以如果我的问题有问题或者您需要其他任何内容,请告诉我。

所以。我这里有这段代码:(我使用 SFML 作为矢量和 CircleShape)

Ball::Ball() 

    // This ugly thing calls the full constructor with a random x and y position
    // in such a way the the entire ball is inside the screen.

    Ball::Ball((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS, (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);


Ball::Ball(float x, float y) 

    loc.x = x;
    loc.y = y;

    ball.setPosition(loc.x - BALL_RADIUS, loc.y - BALL_RADIUS);
    ball.setRadius(BALL_RADIUS);
    ball.setFillColor(sf::Color::Red);
    ball.setOutlineColor(sf::Color::Black);
    ball.setOutlineThickness(1);


这是标题(#included 到上面的文件中):

class Ball 

private:
    sf::CircleShape ball;
    sf::Vector2f loc;
    sf::Vector2f vel;
    sf::Vector2f acc;

    void update();
    void bounce();
    void draw();

public:
    Ball();
    Ball(float x, float y);
    void run();

;

当我用

创建球时
Ball ball;

(是的,所有 SFML 渲染的东西都有效),它永远不会显示。一点调查表明,它的 loc.x 和 loc.y 变量没有设置,可能球对象的半径、填充颜色等也没有设置。如果我用 std::cout inside 打印这些值,构造函数 loc.x 和 loc.y 以及所有其他 设置,所以我假设他们得到在构造函数之后的某个地方取消设置。奇怪的是,如果我用

Ball ball((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS, (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);

甚至

Ball ball(400, 300);

一切正常,球出现在屏幕上。 我真的很难过伙计们。如果有人可以帮助我,那就太好了。

顺便说一句,我正在运行带有 Xcode 4.5.2 的 OS X 10.8,并使用 SFML RC2.0,如果这有什么不同的话。

谢谢,

马特

【问题讨论】:

感谢大家这么快的回复!我将创建一个由两个构造函数调用的 init() 函数,因为这似乎是做我想做的最好的方法。从 Java 迁移到 C++ 令人困惑。 【参考方案1】:

在 C++11 之前,从另一个构造函数调用构造函数(称为委托构造函数)是不可能的。要在 C++11 中做到这一点,您需要使用成员初始化列表:

Ball::Ball()
 : Ball((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS,
        (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS)
 

在 C++11 之前,您可以创建另一个函数来完成常见工作并让两个构造函数都调用它。

Ball::Ball() 
  init((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS,
       (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);


Ball::Ball(float x, float y) 
  init(x, y);


void Ball::init(float x, float y) 
  loc.x = x;
  loc.y = y;

  ball.setPosition(loc.x - BALL_RADIUS, loc.y - BALL_RADIUS);
  ball.setRadius(BALL_RADIUS);
  ball.setFillColor(sf::Color::Red);
  ball.setOutlineColor(sf::Color::Black);
  ball.setOutlineThickness(1);

【讨论】:

而不是 init 函数,它有点难看并且会导致新手走向不良的两阶段构造,而是考虑一个子对象:数据成员或基类(不管哪个) @Alf:如果 init() 是私有的,那么该解决方案一点也不差。【参考方案2】:

C++ 11 之前的 C++ 不支持构造函数链接

您可以将逻辑带到一个函数中,并从两个构造函数中调用它。类似:

Ball::Ball() 

    // This ugly thing calls the full constructor with a random x and y position
    // in such a way the the entire ball is inside the screen.

   init((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS, (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);



Ball::Ball(float x, float y) 

    init(x,y);



Ball::init(float x, float y) 

    loc.x = x;
    loc.y = y;

    ball.setPosition(loc.x - BALL_RADIUS, loc.y - BALL_RADIUS);
    ball.setRadius(BALL_RADIUS);
    ball.setFillColor(sf::Color::Red);
    ball.setOutlineColor(sf::Color::Black);
    ball.setOutlineThickness(1);


【讨论】:

【参考方案3】:

不允许在 C++ 中使用构造函数链接,而是会创建一个临时版本的类,而不是在任何地方分配,然后丢弃。

相反,使用您想要的参数创建一个私有初始化方法,并使用正确的参数从您的构造函数中调用它。

【讨论】:

+1 用于提及问题中的语法的作用,而不仅仅是说明如何使其工作。 我没有投反对票,但现在允许/可以使用构造函数链接/委托。有些人只是超级挑剔。【参考方案4】:

C++ 不支持构造函数链接,除非您使用的是 C++ 11,我认为您不使用。

详情请看这个答案:

LINK

【讨论】:

【参考方案5】:

我建议不要使用构造函数链接,而是使用两阶段初始化,这意味着您创建一个在默认构造函数中调用的 init() 函数。

【讨论】:

【参考方案6】:

其他答案给出了执行此操作的语法正确方法。

我会做一些语义上正确的事情,以便你这样称呼它:

Ball ball = Ball::createRandom();

您将createRandom 实现为Ballstatic 函数:

class Ball 
public:
    //...
    static Ball createRandom();
;

实现为:

int randomisePosition(int position) 
    return (rand() % (position - (2 * BALL_RADIUS))) + BALL_RADIUS;


Ball Ball::createRandom() 
    return Ball(randomisePosition(WINDOW_X),
                randomisePosition(WINDOW_Y));

【讨论】:

+1 不要试图盲目地修改代码,而是考虑用户需要什么。 谢谢。我试试。这并不总是回答问题的正确方式,也并不总是得到支持,但我并不是想成为最好的单一答案。我想扩展上下文。【参考方案7】:

你应该创建一个 init() 方法并在你的两个构造函数中调用它。

Ball::Ball((rand() % (WINDOW_X - (2 * BALL_RADIUS))) + BALL_RADIUS, (rand() % (WINDOW_Y - (2 * BALL_RADIUS))) + BALL_RADIUS);

创建一个临时球对象并立即销毁它

【讨论】:

以上是关于默认构造函数的奇怪错误(C++)的主要内容,如果未能解决你的问题,请参考以下文章

错误:在构造函数(C++)中没有重载函数的实例

std::array 实现上的隐式构造函数的奇怪错误

C++ 中“覆盖函数的异常规范比基本版本更宽松”的奇怪错误

为啥这个非常简单的构造函数会导致段错误?

C++ - 链表 - 复制构造函数

默认复制/移动构造函数时 GDB 中的奇怪行为