在C++中创建一个类的实例向量

13

我创建了一个类,它的名字叫做Student,代码如下:

class Student
{
 private:
     unsigned int id;                                // the id of the student 
public:   
    unsigned int get_id(){return id;};   
    void set_id(unsigned int value) {id = value;};
    Student(unsigned int init_val) {id = init_val;};   // constructor
    ~Student() {};                                     // destructor
};

然后我想要一个容器(比如一个向量),它的元素是Student类的实例,但我发现自己无法理解这种情况,以下是我的问题:

我首先运行了这段代码:

#include<iostream>
#include<vector>
using namespace std;

const unsigned int N = 5;

Student ver_list[2] = {7, 9};


int main()
{

  cout<< "Hello, This is a code to learn classes"<< endl;

  cout<< ver_list[1].get_id() << endl;

return 0;
}

一切顺利,输出结果为:

Hello, This is a code to learn classes
9

现在当我尝试以下选项:

选项 #1:

#include<iostream>
#include<vector>
using namespace std;

const unsigned int N = 5;

vector <Student> ver[N];             // Create vector with N elements
for(unsigned int i = 0; i < N; ++i )
ver[i].set_id(i); 


int main()
{

  cout<< "Hello, This is a code to learn classes"<< endl;

  cout<< ver[1].get_id() << endl;

return 0;
}

我得到了这个输出:"错误":

test.cpp:26:3: error: expected unqualified-id before 'for'
   for(unsigned int i = 0; i < N; ++i )
   ^
test.cpp:26:27: error: 'i' does not name a type
   for(unsigned int i = 0; i < N; ++i )
                           ^
test.cpp:26:34: error: expected unqualified-id before '++' token
   for(unsigned int i = 0; i < N; ++i )
                                  ^
test.cpp: In function 'int main()':
test.cpp:43:15: error: 'class std::vector<Student>' has no member named 'get_id'

 cout<< ver[1].get_id() << endl;
               ^

选项 #2:

#include<iostream>
#include<vector>
using namespace std;

const unsigned int N = 5;

Student ver[N];                       // Create one dimensional array with N elements
for(unsigned int i = 0; i < N; ++i )
   ver[i].set_id(i); 


int main()
{

  cout<< "Hello, This is a code to learn classes"<< endl;

  cout<< ver[1].get_id() << endl;

return 0;
}

输出的 "error" 是 :

test.cpp:30:14: error: no matching function for call to 'Student::Student()'
Student ver[5];
             ^
test.cpp:30:14: note: candidates are:
test.cpp:14:2: note: Student::Student(unsigned int)
  Student(unsigned int init_val) {id = init_val;};   // constructor
  ^
test.cpp:14:2: note:   candidate expects 1 argument, 0 provided
test.cpp:7:7: note: Student::Student(const Student&)
 class Student
       ^
test.cpp:7:7: note:   candidate expects 1 argument, 0 provided
test.cpp:31:1: error: expected unqualified-id before 'for'
 for(unsigned int i = 0; i < N; ++i )
 ^
test.cpp:31:25: error: 'i' does not name a type
 for(unsigned int i = 0; i < N; ++i )
                         ^
test.cpp:31:32: error: expected unqualified-id before '++' token
 for(unsigned int i = 0; i < N; ++i )
                                ^

第一次尝试时一切看起来都很好,但当我尝试了接下来的两个选项后,我收到了错误提示,我希望我能理解我做错了什么。

谢谢。


1
首先,把运算符放在一个函数中,C++不允许在函数外使用运算符。 - billz
如果我没记错的话,如果你有一个带参数的构造函数,C++ 就不会创建默认构造函数,这就是为什么出现了“no matching function for call to 'Student::Student()'”的原因。因此,在你的 Student 类的公共部分中添加 ´Student() {}´。 - Verena Haunschmid
1
vector <Student> ver[N]; 这样并不会创建一个含有 N 个学生的向量,而是创建了一个包含 N 个 vector<Student> 元素的数组。如果你想要创建一个含有 N 个学生的向量,可以使用 vector<Student> ver(N); - RedX
@ExpectoPatronum:拥有一个不正确初始化对象的构造函数是个坏主意。同时,两阶段初始化也是个坏主意。因此,这个类的默认构造函数不是好主意。 - Martin York
@LokiAstari 好的,我之前不知道,那他/她的代码就不能工作了,对吗?一个类里面有多个构造器通常不是个好主意,是吗? - Verena Haunschmid
1
@ExpectoPatronum:拥有多个构造函数是完全可以的。问题在于在构造函数完成后将对象保留在不良(未初始化或未定义)状态。 - Martin York
6个回答

29

这个:

vector <Student> ver[N];

创建一个包含N个元素的数组。每个元素都是vector<Student>。这不是你想要的。你可能想要创建一个包含N个元素的向量。其语法为:

vector <Student> ver(N);

但是你不能使用它,因为你的类没有默认构造函数。所以你的下一个选择是使用相同元素初始化所有对象。

vector <Student> ver(N, Student(0));

您还尝试像这样创建一个学生数组:

Student ver[N];

这不会起作用。因为它尝试使用默认构造函数来初始化数组中的每个元素。但是你的类没有默认构造函数,所以这不会起作用。但这就是为什么你原来的代码能够工作的原因:
Student ver_list[2] = {7, 9};  // Here you are using the constructor for your object.
                               // It uses the normal constructor you provided not the default one.

另一个问题是您不能在函数(方法)外部运行代码。
因此,下面的代码不起作用:
for(unsigned int i = 0; i < N; ++i )
    ver[i].set_id(i); 

在C++11中,你可以像初始化数组一样初始化向量(vector):
vector<Student>  ver = { 0, 1, 2, 3, 4, 5};

如果你没有C++11或者初始化过于复杂,那么你需要编写一个包装器。

class VecWrapper
{
     public:
         std::vector<Student>   ver;
         VecWrapper()
         {
            ver.reserve(N);
            for(unsigned int i = 0; i < N; ++i )
                ver.push_back(Student(i));
         }
 };

现在你可以将它放在全局范围内并自动初始化。
 VecWrapper   myData;  // myData.vec  initializaed before main entered.

 int main()
 {}

完整解决方案:

选项 2:

#include<iostream>
#include<vector>
using namespace std;

const unsigned int N = 5;

// The following is not correct
// This creates an arrya of `N` elements each element is `vector <Student>`
//
// vector <Student> ver[N];             // Create vector with N elements
// 

// The following lines are not allowed.
// All code has to be inside a function.
//
// for(unsigned int i = 0; i < N; ++i )
// ver[i].set_id(i); 


// What you want is:
//    I use the following because it is unclear if you have C++11 or not.  
class VecWrapper
{
   public:
     std::vector<Student>   vec;
     VecWrapper()
     {
        vec.reserve(N);
        for(unsigned int i = 0; i < N; ++i )
            vec.push_back(Student(i));
     }
};
VecWrapper   myData;  // myData.vec 
int main()
{

  cout<< "Hello, This is a code to learn classes"<< endl;

  cout<< myData.vec[1].get_id() << endl;

return 0;
}

让我先说,你的答案部分运作得比所有其他答案都好,但我觉得我要么很蠢,要么是被选项压垮了,因为我无法让它们都运作起来。我认为我可能在某个地方有问题,也许是在向量方面,我无法编写完整的代码让它工作,每次我改变一些东西,就会出现其他类型的错误。Loki,你能否编辑你的答案并使其成为完整的代码以查看是否有效,我感觉现在像迷失了方向,我只是收到了建议,但没有一个可以解决这些错误消息。 - mazlor
我收到了这个错误信息 test.cpp:104:18: error: 'Student' was not declared in this scope std::vector<Student> vec; ^ test.cpp:104:25: error: template argument 1 is invalid std::vector<Student> vec; ^ test.cpp:104:25: error: template argument 2 is invalid test.cpp: 在构造函数 'VecWrapper::VecWrapper()' 中: test.cpp:107:13: error: 对非类类型 'int' 的 '((VecWrapper*)this)->VecWrapper::vec' 请求成员 'reserve' vec.reserve(N); ^ - mazlor
@mazlor:提示在错误信息的前三个单词中。你应该能够解密它。 - Martin York
现在它已经完美运作了,我现在得去学习包装器了。非常感谢你,Loki,我很感激你所做的一切。 - mazlor

2
主要问题是您试图在全局范围内执行for循环。定义和初始化变量可以在函数外部进行,但是不可以使用for循环或赋值运算符。将for循环放入main()中(并且我建议您也将N、vector / student数组放入main()中),一切都应该正常工作。
此外,编译器发出警告,因为当您声明Student array[5];vector<Student> ver[N];时,它正在寻找名为Student()的默认构造函数,该函数仅为类设置默认值。您需要在Student类中提供这个函数;将id设置为永远不可能是实际学生ID的某个值,例如-1。

允许创建无效对象并不是一个好主意。另外,vector<Student> ver[N]; 是可以的。每个 N 个向量在构造时都是空的。因此,没有创建任何 Student 对象,也没有违反任何约束。 - Martin York

1

选项#1:

您应该将vector <Student> ver[N]替换为vector<Student> ver(N)

std::vector是一个类,代表向量本身,您不应该创建向量数组,而只需将N(向量大小)传递给它的构造函数即可。 请查看link

选项#2:

Student ver[N];

这是错误的,因为会调用默认构造函数Student() N次,但你没有实现它。 所以你必须使用数组初始化器Student ver[5] = {1, 2, 3, 4, 5}或者显式地实现默认构造函数。

当然 - "for"循环必须在函数体内使用。


1
    #include<iostream>

    using namespace std;

    class Student
    {
        private:
        int id;

        public:
        // Mutator
        void setId(int i)
        {
          id = i;
        }
        // Accessor
        int getId()const
        {
          return id;
        }
    };

    int main()
    {
        const unsigned int N = 5;
        Student ver[N];   // Define instances as an array 
        // of the Student class

        int idStudent[N] = { 11, 32, 37, 4, 50};  // Create 
        // one dimensional array with N elements of the 
        // student ID

        for(unsigned int i = 0; i < N; i++ ){ // Assign 
        //student ID for each object of the class
        ver[i].setId(idStudent[i]);}

        cout<< "Hello, This is a code to learn classes : "
        << endl << endl; // Display the student ID

        for(unsigned int i = 0; i < N; i++ ){
        cout<< "Student ID #"  << i+1 << " of "
        << N << " : " << ver[i].getId() << endl;}

        return 0;

    }

0
解决这个问题的方法是创建一个学生类实例数组,如Student ver[N]。接下来,使用修改器函数setID(int i)将给定的学生ID数组(int idStudent[N] = {11, 32, 37, 4, 50};)中的元素分配给每个透视学生类实例:ver[i].setId(idStudent[i]),并使用for循环完成任务。
最后,使用访问器函数ver[i].getID()和for循环显示信息。

欢迎来到SO。请使用代码中的注释格式化答案解释。 - Harshal Parekh

0

这实际上与向量没有任何关联。 你只需要将你的“for”语句移动到主函数中即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接