0

Trying to create a class. When i put { after constructor, vs2015 shows me an error

No default constructor is available for the specified class, structure, or union.

Theres a code snippets:

NumberExpression.h:

class NumberExpression : Expression {
private:
    Token m_token;
public:
    NumberExpression(Token tok);
    double evaluate();
};

NumberExpression.cpp:

NumberExpression::NumberExpression(Token tok) {
    m_token = tok;
}

Token.h:

class Token {
public:
    enum TYPE { NUM, ADD, SUB, MUL, DIV, EoF };
private:
    char* m_text;
    TYPE m_type;
public:
    Token(TYPE type, char* text);

    TYPE getType() const { return m_type; }
    char* getText() const { return m_text; }
};

I know that i can just create an Empty constructor, but why this error happens?

3 Answers3

3
NumberExpression::NumberExpression(Token tok) {
    m_token = tok;
}

is equivalent to

NumberExpression::NumberExpression(Token tok) : m_token() {
    m_token = tok;
}

Since Token does not have a default constructor, the compiler complains. And rightly so.

Change that to use a valid constructor of Token.

NumberExpression::NumberExpression(Token tok) : m_token(tok) {}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

You should initialize m_token via member intializer list directly.

For members that cannot be default-initialized, such as members of reference and const-qualified types, member initializers must be specified.

e.g.

NumberExpression::NumberExpression(Token tok) : m_token(tok) {
}

In your implementation, m_token will be default initialized at first, then assigned in the body of the constructor of NumberExpression. But Token doesn't have a default constructor.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
1

The OP asked this:

I know that i can just create an Empty constructor, but why this error happens?

Your class NumberExpression has a constructor that takes a Token object.

In this class's constructor body you are using Token's copy assignment operator. m_token = tok; that is defined by the compiler by default.

In your class Token the constructor that you declared & defined is expecting 2 parameters in its parameter list. Yet when you try to use the copy assignment operator this is why the compiler is giving you that error. You are trying to assign a copy of a Token object and save(store) it to a member of NumberExpression. Since you declared a constructor for Token that takes two parameters the compiler will not use the default ctor or copy ctor because you have not supplied one after declaring a user defined constructor and it can not find the declaration or definition of a default ctor.


There are three ways to fix this:

  1. Provide a Default or empty constructor in the header simply as:

    • Token() = default;
    • Token();
    • Token() {}
  2. Use NumberExpression's class member initializer list as others have stated:

    • NumberExpression::NumberExpression( Token token ) : m_token( token ) {...}
  3. Or use both in combination.

Also since you are passing a single object into NumberExpression's constructor if you want to prevent automatic implicit conversion or casting by the compiler and want to make it strict you can use the explicit keyword on the Constructor's declaration:

class NumberExpression : public Expression {
private: 
    Token m_token;
public:
    explicit NumberExpression( Token token ) : m_token( token ) {}
    double evaluate();
};

To set the default initialization list for the token class:

class Token {
public:
    enum Type {
        INVALID = -1,
        NUM,
        ADD,
        SUB,
        MUL,
        DIV,
        EOF
    };
private:
    char* m_text;
    Type m_type;
public:
    Token(Type type, char* text) : m_type(INVALID), m_text(nullptr) {}

    Type getType() const { return m_type; }
    char* getText() const { return m_text; }
};
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • What is the default initialization value of enum? – ValentaTomas Dec 20 '17 at 05:38
  • @Davar The OP can add another enum value before all others such as `enum { INVALID = -1, all others, };` Then set that in the initializer list. – Francis Cugler Dec 20 '17 at 05:40
  • That's true, but I was more interested in the question if the enums are default constructible and what is their behavior like. – ValentaTomas Dec 20 '17 at 05:46
  • @Dava that's actually a good question; not sure if they are default constructible or not (don't remember), but I do believe that they are of an integer type... – Francis Cugler Dec 20 '17 at 05:47
  • 1
    @Francio Cigler I tested it - they seem to be be default AND trivially AND nothrow constructible (http://en.cppreference.com/w/cpp/types/is_default_constructible), but without namespace scope they really have undefined behavior (they are of value 0 in namespace). There is also similar question: https://stackoverflow.com/questions/6842799/enum-variable-default-value – ValentaTomas Dec 20 '17 at 06:01
  • @Davar Yeah I think I just read that question too. – Francis Cugler Dec 20 '17 at 06:10