如何使用自定义类声明数组

How do I declare an array with a custom class?

本文关键字:声明 数组 自定义 何使用      更新时间:2023-10-16

我试图用自定义类声明一个数组。当我向类添加构造函数时,我的编译器报错"没有匹配name[3]初始化的构造函数"。

这是我的程序:

#include <iostream>
using namespace std;
class name {
  public:
    string first;
    string last;
  name(string a, string b){
    first = a;
    last = b;
  }
};
int main (int argc, const char * argv[])
{
  const int howManyNames = 3;
  name someName[howManyNames];
  return 0;
}

我能做些什么来运行,我做错了什么?

必须提供一个默认构造函数。同时,也修复其他构造函数:

class Name
{
public:
  Name() { }
  Name(string const & f, string const & l) : first(f), last(l) { }
  //...
};

或者,您必须提供初始化式:

Name arr[3] { { "John", "Doe" }, { "Jane", "Smith" }, { "", "" } };

后者在概念上更可取,因为您的类没有理由具有"默认"状态的概念。在这种情况下,只需为数组的每个元素提供适当的初始化式。

c++中的

对象永远不能处于定义不清的状态;如果你这样想,一切都应该变得很清楚了。


另一种选择是使用动态容器,尽管这与您要求的不同:

std::vector<Name> arr;
arr.reserve(3);  // morally "an uninitialized array", though it really isn't
arr.emplace_back("John", "Doe");
arr.emplace_back("Jane", "Smith");
arr.emplace_back("", "");
std::vector<Name> brr { { "ab", "cd" }, { "de", "fg" } }; // yet another way

要默认初始化T数组,T必须是默认可构造的。通常编译器会免费给你一个默认构造函数。但是,由于您自己声明了构造函数,编译器不会生成默认构造函数。

你的选择:

  • 添加一个默认构造函数到name,如果这是有意义的(我不这么认为,但我不知道问题域);
  • 在声明时初始化数组的所有元素(您可以这样做,因为name是聚合);

      name someName[4] = { { "Arthur", "Dent" },
                           { "Ford", "Prefect" },
                           { "Tricia", "McMillan" },
                           { "Zaphod", "Beeblebrox" }
                         };
    
  • 使用std::vector代替,并且只在构建元素时添加元素。

您需要一个无参数构造函数来创建类的实例。当前构造函数需要两个输入字符串参数。

如果没有声明其他构造函数,通常c++意味着有这样一个构造函数(=默认的无参数构造函数)。通过用两个参数声明你的第一个构造函数,你覆盖了这个默认行为,现在你必须显式声明这个构造函数。 下面是工作代码:
#include <iostream> 
#include <string>  // <-- you need this if you want to use string type
using namespace std; 
class name { 
  public: 
    string first; 
    string last; 
  name(string a, string b){ 
    first = a; 
    last = b; 
  }
  name ()  // <-- this is your explicit parameterless constructor
  {}
}; 
int main (int argc, const char * argv[]) 
{ 
  const int howManyNames = 3; 
  name someName[howManyNames]; 
  return 0; 
}

(顺便说一句,你需要包含使代码可编译。)

另一种方法是在声明

时显式初始化实例
  name someName[howManyNames] = { {"Ivan", "The Terrible"}, {"Catherine", "The Great"} };

为了创建一个对象数组,对象需要一个不带任何参数的构造函数(它创建对象的默认形式,例如:两个字符串都为空)。这就是错误消息的含义。编译器自动生成一个构造函数,该构造函数创建一个空对象,除非存在其他构造函数。

如果将数组元素创建为空有意义(在这种情况下,成员获取其默认值,在这种情况下为空字符串),则应该:

-写一个空构造函数:

class name {
  public:
    string first;
    string last;
  name() { }
  name(string a, string b){
    first = a;
    last = b;
  }
};

-或者,如果你不需要它,删除现有的构造函数。

如果类的"空"版本没有意义,则没有好的解决方案在编译时为数组的所有元素提供初始化参数。您可以:

  • 有一个构造函数创建一个空版本的类,和一个init()函数做真正的初始化
  • 使用vector,在初始化时创建对象并将它们插入vector,使用vector::insert或循环,并且相信在编译时不这样做并不重要。
  • 如果对象也不能被复制,你可以使用智能指针的数组/向量指向对象,并在初始化时分配它们。
  • 如果你可以使用c++ 11,我认为(?)你可以使用初始化器列表来初始化向量并初始化它(我不确定这是否适用于任何构造函数,或者仅当对象是从另一种类型的单个值创建的)。例如:。
 std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };

"

你只需要添加一个默认构造函数到你的类,看起来像这样:

class name {
  public:
    string first;
    string last;
  name() {
  }
  name(string a, string b){
    first = a;
    last = b;
  }
};

您的class:

class name {
  public:
    string first;
    string last;
  name() { }  //Default constructor.
  name(string a, string b){
    first = a;
    last = b;
  }
};

有一个显式的构造函数,需要两个字符串形参。没有显式编写构造函数的类获得不带参数的默认构造函数。添加显式构造函数会阻止编译器为您生成默认构造函数。

因此,如果您希望创建一个未初始化对象的数组,请为您的类添加一个默认构造函数,以便编译器知道如何在不提供这两个字符串参数的情况下创建它们—参见上面的注释行。