【问题标题】:How do I declare an array with a custom class?如何使用自定义类声明数组?
【发布时间】:2011-12-20 17:50:38
【问题描述】:

我正在尝试使用自定义类声明一个数组。当我向类添加构造函数时,我的编译器抱怨说“没有匹配的构造函数用于初始化名称 [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;
}

我该怎么做才能让它运行,我做错了什么?

【问题讨论】:

    标签: c++ arrays constructor


    【解决方案1】:

    您必须提供一个默认构造函数。当你在做的时候,也修复你的另一个构造函数:

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

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

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

    后者在概念上更可取,因为你的类没有理由应该有“默认”状态的概念。在这种情况下,您只需必须为数组的每个元素提供适当的初始化程序。

    C++ 中的对象永远不会处于定义不明确的状态;这么一想,一切都应该很清楚了。


    另一种方法是使用 dynamic 容器,尽管这与您要求的不同:

    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
    

    【讨论】:

    • POD 可能处于不明确的状态 ;)
    • @FredOverflow:它们不是“定义不明确的”——它们是“未初始化的”,在概念上定义明确,具有您不能阅读它们的语义。
    • 好的,那么可能处于不明确状态的示例是什么?
    • @FredOverflow:好吧,正如我所说,你不能在 C++ 中做到这一点。假设它类似于制作一个“未构造”对象的静态数组——对象不处于明确定义状态的任何东西(例如,在没有完成构造函数的情况下尝试将内存作为类类型对象寻址)。也许新的不受约束的工会提供了更多的例子;如果您没有以正确的顺序运行自己的析构函数,那么那里有很多 UB;暗示禁止您驾车进入不明确的状态。
    • 呃,resize 需要一个默认的可构造类型。
    【解决方案2】:

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

    您的选择:

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

        name someName[4] = { { "Arthur", "Dent" },
                             { "Ford", "Prefect" },
                             { "Tricia", "McMillan" },
                             { "Zaphod", "Beeblebrox" }
                           };
      
    • 改用std::vector,并且仅在构造它们时添加元素。

    【讨论】:

      【解决方案3】:

      您需要parameterless constructor 才能创建您的类的实例。您当前的构造函数需要两个输入字符串参数。

      如果没有声明其他构造函数,通常 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"} };
      

      【讨论】:

        【解决方案4】:

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

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

        -写一个空的构造函数:

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

        `

        【讨论】:

          【解决方案5】:

          您只需要向您的类添加一个默认构造函数,如下所示:

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

          【讨论】:

            【解决方案6】:

            你的班级:

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

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

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

            【讨论】:

              猜你喜欢
              • 2014-10-13
              • 1970-01-01
              • 1970-01-01
              • 2013-08-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多