Error C2512: no appropriate default constructor available - Why if properties are being initialized in constructor?

StackOverflow https://stackoverflow.com/questions/23283429

  •  09-07-2023
  •  | 
  •  

Question

I've been searching for quite a while now and can't find anyone in my situation. Sorry if this is a duplicate.

I have a Game class, defined in Game.h:

class Game
{
    public:
        Game(int argc, char **argv);
        ~Game();

    private:
        Logger logger;
        Stage stage;
        Engine engine;
};

Then in Game.cpp:

Game::Game(int argc, char **argv)
{
        // Some code removed for clarity. Consider filename and bitsPerPixel 
        // already defined.

        string fileName;
        if (argc != 2){
            fileName = defaultYAMLFilename;
            logger.logBadParam(argc, fileName);
        } else {
            fileName = argv[1];
        }

        logger = Logger();

        stage = Stage(fileName);

        engine = Engine(stage.getWidthPx(), stage.getHeightPx(), bitsPerPixel, stage.getTimeStep());
}

And then I get this error:

game.cpp(7): error C2512: 'WormsModel::Stage' : no appropriate default constructor available

game.cpp(7): error C2512: 'Engine' : no appropriate default constructor available

Why if properties are being initialized in constructor? OK, I understand Chris's comment about Initialization lists. How could I manage to evaluate argc and all that to initialize Stage?

Was it helpful?

Solution

There is an implicit construction with no parameters whenever you have fields in a class. If you want to initialize the fields using a non-default constructor, you have to use initializers, like so:

Game::Game(int argc, char **argv) : logger(), 
                                    stage(fileName), 
                                    engine(stage.getWidthPx(), 
                                           stage.getHeightPx(), 
                                           bitsPerPixel, 
                                           stage.getTimeStep())
{
     /* remainder of constructor here */
}

Except that this won't likely work since you probably did some work inside the constructor to initialize fileName and bitsPerPixel. But this is the problem you are encountering. How you address it is up to you.

Every constructor must call a constructor for each of the fields in the class. If you don't specify which constructor, it will be the default. You could, however, make the fields pointers to the objects. Then they can initialize to NULL and you can create them with new inside the constructor.

OTHER TIPS

Here's a better way to do complex processing before member initialization, without making object lifetime complicated with pointers:

struct GameOptions
{
    std::string YAMLFilename;

    GameOptions(int argc, char** argv);
};

GameOptions::GameOptions(int argc, char** argv)
{
    if (argc != 2){
        YAMLFilename = defaultYAMLFilename;
        logger.logBadParam(argc, fileName);
    } else {
        YAMLFilename = argv[1];
    }
}

Game::Game(GameOptions&& opts) : logger()
                               , stage(opts.YAMLFilename )
                               , engine(stage.getWidthPx(), 
                                        stage.getHeightPx(), 
                                        bitsPerPixel, 
                                        stage.getTimeStep())
{
     /* remainder of constructor here */
}

And call it as

Game theGame(GameOptions(argc, argv));

or even

Game theGame({argc, argv});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top