【问题标题】:No default constructor is available for the specified class, structure, or union [duplicate]指定的类、结构或联合没有可用的默认构造函数[重复]
【发布时间】:2018-06-02 14:26:18
【问题描述】:

试图创建一个类。当我将{ 放在构造函数之后时,vs2015 显示错误

没有可用于指定类、结构或联合的默认构造函数。

有一个代码sn-ps:

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

我知道我可以只创建一个 Empty 构造函数,但是为什么会发生这个错误?

【问题讨论】:

    标签: c++ constructor


    【解决方案1】:

    你应该直接通过member intializer list初始化m_token。

    对于不能默认初始化的成员,例如引用和 const 限定类型的成员,必须指定成员初始化器。

    例如

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

    在你的实现中,m_token 首先会被默认初始化,然后在NumberExpression 的构造函数体中赋值。但是Token 没有默认构造函数。

    【讨论】:

      【解决方案2】:
      NumberExpression::NumberExpression(Token tok) {
          m_token = tok;
      }
      

      等价于

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

      由于Token 没有默认构造函数,编译器会报错。没错。

      将其更改为使用 Token 的有效构造函数。

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

      【讨论】:

        【解决方案3】:

        OP 这么问:

        我知道我可以只创建一个 Empty 构造函数,但是为什么会出现这个错误?

        您的类NumberExpression 有一个构造函数,它接受Token 对象。

        在此类的构造函数主体中,您使用的是Token's 复制赋值运算符。 m_token = tok; 由编译器默认定义。

        在您的类 Token 中,您声明和定义的构造函数在其参数列表中需要 2 个参数。然而,当您尝试使用复制赋值运算符时,这就是编译器给您该错误的原因。您正在尝试分配 Token 对象的副本并将其保存(存储)给 NumberExpression 的成员。由于您为带有两个参数的Token 声明了constructor,因此编译器将不会使用默认的ctor 或copy ctor,因为您在声明user defined constructor 后没有提供一个,并且它找不到声明或定义默认ctor。


        有三种方法可以解决这个问题:

        1. 在标头中提供默认或空构造函数,如下所示:

          • Token() = default;
          • Token();
          • Token() {}
        2. 如其他人所说,使用NumberExpression's 类成员初始化器列表:

          • NumberExpression::NumberExpression( Token token ) : m_token( token ) {...}
        3. 或两者结合使用。

        此外,由于您将单个对象传递给 NumberExpression's 构造函数 如果您想防止编译器自动进行隐式转换或强制转换并使其严格,您可以在构造函数声明中使用 explicit 关键字:

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

        设置令牌类的默认初始化列表:

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

        【讨论】:

        • 枚举的默认初始化值是多少?
        • @Davar OP 可以在所有其他枚举值之前添加另一个枚举值,例如 enum { INVALID = -1, all others, }; 然后在初始化列表中设置它。
        • 没错,但我更感兴趣的是枚举是否默认可构造以及它们的行为是什么样的。
        • @Dava 这实际上是一个好问题;不确定它们是否是默认可构造的(不记得了),但我相信它们是整数类型...
        • @Francio Cigler 我对其进行了测试-它们似乎是默认的,并且很简单,并且不能构造(en.cppreference.com/w/cpp/types/is_default_constructible),但是没有命名空间范围,它们确实具有未定义的行为(它们在命名空间中的值为 0) .还有类似的问题:stackoverflow.com/questions/6842799/enum-variable-default-value
        猜你喜欢
        • 2011-12-22
        • 2013-10-14
        • 1970-01-01
        • 2016-04-22
        • 1970-01-01
        • 2020-05-19
        • 1970-01-01
        • 2017-08-15
        • 1970-01-01
        相关资源
        最近更新 更多