【问题标题】:Constructor with multiple parameters throws 'expression list treated as compound expression in initializer' when array of classes declared声明类数组时,具有多个参数的构造函数会抛出“在初始化程序中被视为复合表达式的表达式列表”
【发布时间】:2021-12-17 07:30:07
【问题描述】:

我创建了以下测试程序来演示我似乎无法解决的错误。我搜索并阅读了几篇文章,但没有一篇文章解释了如何解决这个特定问题。

我创建了一个具有多个构造函数的类,其中一个具有多个参数。我可以声明测试每个构造函数的类的实例,但是当我声明一个类数组时,我只能使用默认构造函数或带有单个参数的版本。

当我创建一个类数组并尝试使用多参数构造函数时,出现编译错误:“表达式列表在初始化程序 [-fpermissive] 中被视为复合表达式”。我正在使用 C++11 mingw 编译器,请参阅下面示例程序中的 kc5。

谁能解释一下错误的含义,以及当构造函数有多个参数时如何正确声明一个类对象数组?

#include <iostream>
using namespace std;

class KClass {
public:
int x=0;

KClass(){};//default constructor w/o parameters works

KClass(int a){//single parameter constructor works
x = a;
return;
}

KClass(char c,int a){//multi parameter constructor
x = a;
//not using char c for now
return;
}

~KClass(){};//destructor

int getx(){return x;}
void setx(int data){x=data;return;}
};

//class is declared, let's create some instances of the class
KClass kc0;//works
KClass kc1(5);//works
KClass kc2('k',7);//works
KClass kc3[2];//works
KClass kc4[2](4);//works
//next line does not compile (how do I fix?)
KClass kc5[2]('r',4);//compile error: expression list treated as compound expression in initializer

int main()
{
//do something

  getchar();
  return 0;
}

我了解到使用“new”关键字有效,但是,该解决方案对我来说似乎并不优雅,我不明白为什么需要“new”。

KClass *kc6 = new KClass[2]; //works

然后在 main() 中我使用多参数构造函数进行初始化。

kc6[0] = KClass('a',2);
kc6[1] = KClass('b',3);

【问题讨论】:

  • C++ 中没有办法做你想做的事。使用std::vector 代替数组。
  • 你的代码是KClass kc4[2](4);//works ...真的吗?我怎么看不出来! Clang-cl 给出:error : array initializer must be an initializer list。但在使用 C++20 标准时,它似乎在 MSVC 中工作。
  • 是的,KClass[2](4);使用 C++11 工作(基于我的测试)

标签: c++ class constructor initialization


【解决方案1】:

这样的数组初始化

KClass kc5[2]('r',4);

C++ 20 标准允许。在这种情况下,将为每个元素调用带有一个参数的构造函数。

如果编译器不支持 C++ 20 标准,则会报错。

否则在 C++ 20 中你可以编写

KClass kc5[2]( { 'r',4 } );

对于第一个元素,将调用带有两个参数的构造函数。

【讨论】:

  • 我找到了一种使用 C11 标准的方法,接下来我将发布(示例程序)。谢谢。
【解决方案2】:

感谢弗拉德的回答。我想补充一点,我学会了如何使用 C++11 标准(下面的示例程序)进行这项工作。

看来我的问题是由于不知道在将多参数构造函数与数组一起使用时使用的正确语法造成的。示例程序显示了有效的方法和意外的结果。

因为我在堆上创建了 3 个类对象,所以我小心翼翼地在程序终止之前删除了这些对象以避免内存泄漏(注意初学者)。

#include <iostream>
using namespace std;

class KClass {
public:
int x=0;

KClass(){
cout << "default constructor called" << endl;
};//default constructor w/o parameters works

KClass(int a){//single parameter constructor works
x = a;
cout << "single parameter constructor a: " << a << endl;
return;
}

KClass(char c,int a){//multi parameter constructor
    cout << "visiting multi param constructor c: " << c << " a: " << a << endl;
x = a;
//not using char c for now
return;
}

~KClass(){
cout << "default destructor" << endl;
};//destructor

int getx(){return x;}
void setx(int data){x=data;return;}
};

//class is declared, let's create some instances of the class
KClass kc0;//works default constructor
KClass kc1(5);//works single parameter constructor
KClass kc2('k',7);//works multi parameter constructor
KClass kc3[2];//works default constructor called twice
KClass kc4[2](4);//works single parameter constructor called twice

//next line does not compile (how do I fix?)
//no compile: KClass kc5[2]('r',4);//compile error: expression list treated as compound expression in initializer

KClass *kc6 = new KClass[2];//defaullt constructor called twice

//notice the syntax needed to call the multiparameter constructor twice
KClass *kc7 = new KClass[2]{{'c',8},{'g',9}};//works  multi parameter constructor called twice

//next line calls the single parameter constructor twice; the char 'd' is treated as int 100 (its ascii int value)
KClass *kc8 = new KClass[2]{'d',6};//works but not as expected single parameter constructor called twice

int main()
{
//do something
kc6[0] = KClass('a',2);
kc6[1] = KClass('b',3);
//use kc7 to prove it worked
cout << "kc7[0].getx(): " << kc7[0].getx() << endl;
cout << "kc7[1].getx(): " << kc7[1].getx() << endl;
cout << endl;
cout << "kc8[0].getx(): " << kc8[0].getx() << endl;
cout << "kc8[1].getx(): " << kc8[1].getx() << endl;
cout << endl;

//because we used the new keyword for kc6, kc7 and kc8:
//those objects are on the heap (vs the stack) so we must manually delete to avoid memory leak
delete []kc6;
kc6=nullptr;
delete []kc7;
kc7=nullptr;
delete []kc8;
kc8=nullptr;

  getchar();
  return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多