C++ - 初始化指针的静态向量导致未定义的引用

C++ - initializing static vector of pointers causes undefined reference

我正在尝试在我的 CreateReport class 中创建一个名为 load() 的函数,该函数将我的 graduate.dat 文件中的所有记录(数据)复制到我的静态记录指针向量中,称为主要收藏。我创建了一个 Record class,其中包含构成每个 Record 的变量,并且在 createReport.ccload() 函数中,我尝试读取文件中的每一行,创建一个 Record object每行,将其添加到我的向量中,然后打印 primaryCollection 中的所有内容。

问题是每次我尝试使用 primaryCollection 时,我都会收到错误消息:

CreateReport.o: In function `CreateReport::CreateReport()':
CreateReport.cc:(.text+0x43): undefined reference to `CreateReport::primaryCollection'
CreateReport.o: In function `CreateReport::load()':
CreateReport.cc:(.text+0x2ac): undefined reference to `CreateReport::primaryCollection'
CreateReport.cc:(.text+0x31d): undefined reference to `CreateReport::primaryCollection'
CreateReport.cc:(.text+0x32f): undefined reference to `CreateReport::primaryCollection'

我在 createReport.cc 中提到 primaryCollection 的 4 次得到了 4 个未定义的引用。我不确定我是否正确地初始化了 primaryCollection 以及这是否是导致这些未定义引用的原因。我不知道这是否与我的问题有关,但 CreateReport 也是一个抽象 class 并且有一些名为 ReportOne、ReportTwo 等的子classes

primaryCollection 应该是 Record 指针的静态向量,我也不允许将 std::map 用于此任务。

对于此问题的任何帮助,我将不胜感激。我看了这个 post Undefined reference to static variable c++ 但我还是不太明白该怎么做。我不允许创建全局变量,我正在处理 collection 而不是单个变量。

我的graduate.dat文件格式如下,格式为<年省学位>

2000 AB Bachelor's 
2005 AB Bachelor's 
2005 MB College 

每一行基本上代表一条记录。所以这里的第一个记录是 2000 AB Bachelor's

编辑:所以我根据评论对我的代码进行了更改,添加了行 vector CreateReport::primaryCollection;在我的构造函数之上,但它给了我错误:

CreateReport.cc:13:34: error: conflicting declaration ‘std::vector<Record*> CreateReport::primaryCollection’
 vector<Record*> CreateReport::primaryCollection;
                                  ^~~~~~~~~~~~~~~~~
In file included from CreateReport.cc:5:0:
CreateReport.h:23:33: note: previous declaration as ‘std::vector<Record*>* CreateReport::primaryCollection’
    static std::vector<Record*>* primaryCollection; //STL vector of record pointers
                                 ^~~~~~~~~~~~~~~~~
CreateReport.cc:13:34: error: declaration of ‘std::vector<Record*>* CreateReport::primaryCollection’ outside of class is not definition [-fpermissive]
 vector<Record*> CreateReport::primaryCollection;

有什么解决办法吗?

Record.h

#ifndef RECORD_H
#define RECORD_H

    #include <iostream>
    #include <string>

    class Record{
      public:
            Record(int = 0, string = "", string = "");
            ~Record();
        
        private:
            int year;
            string province;
            string degree;
    };
    #endif

Record.cc

#include <iostream>
#include <string>
using namespace std;
#include "Record.h"

Record::Record(int i1, string s1, string s2) : year(i1), province(s1), degree(s2){}

Record::~Record(){}

CreateReport.h

#ifndef CREATEREPORT_H
#define CREATEREPORT_H

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cstdlib>

#include "Record.h"

class CreateReport{
  public:
    CreateReport();
    static void load();
  
  protected:
    static vector<Record*> primaryCollection; //STL vector of record pointers
  
};
#endif

CreateReport.cc

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

#include "CreateReport.h"

vector<Record*> CreateReport::primaryCollection;

CreateReport::CreateReport(){ 
}

void CreateReport::load(){
    int year;
    string province, degree;

    ostream_iterator<Record*> outItr(cout);

    ifstream infile("graduate.dat", ios::in); 

    if (!infile) {
        cout << "Error: could not open file" << endl;
        exit(1);
    }

    while (infile >> year >> province >> degree) { //as long as were not at end of file
        Record* record = new Record(year, province, degree); //create Record object with this data
        primaryCollection->push_back(record); //undefined reference
    }
  
    cout<<endl<<"List of Records:"<<endl;
    copy(primaryCollection->begin(), primaryCollection->end(), outItr); //2 undefined references
}

三大问题:

  1. 使用std::vector<*Record>会造成许多un-necessary困难;
  2. 对于静态成员向量,需要在class之外进行额外的定义。std::vector<Record> CreateReport::primaryCollection;。这将清除未定义的错误消息。
  3. 使用复制到std::cout 不起作用,它不提供打印记录的方法。建议写个输出重载。

基于这些,我提供了一个版本如下(将所有 headers 混合在一起。)

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

class Record{
  public:
        Record(int = 0, string = "", string = "");
        ~Record()=default;
 friend  std::ostream& operator<<(std::ostream&, const Record&);
    private:
        int year;
        string province;
        string degree;
};
// **** output overload for Record ***********
    std::ostream& operator<<(std::ostream& os, const Record& rd)
    {
        os << "year = " << rd.year << "  prov = " << rd.province << "  degree = " << rd.degree << std::endl;
       return os;
    }
// ****** end of output overload **************
Record::Record(int i1, string s1, string s2) : year(i1), province(s1), degree(s2){}
//end of Record.cc
//
class CreateReport{
  public:
    CreateReport() = default;
   void load();

  protected:
    static vector<Record> primaryCollection; 
};
//***************** you need this line ********************
vector<Record> CreateReport::primaryCollection;
//*********************************************************
void CreateReport::load(){
   int year;
   string province, degree;

   ifstream infile("graduate.dat", ios::in);

   if (!infile) {
      cout << "Error: could not open file" << endl;
      exit(1);
     }

    while (infile >> year >> province >> degree) {
        primaryCollection.push_back( Record(year, province, degree) );
    }

    cout<<endl<<"List of Records:"<<endl;
    for (int i = 0; i<primaryCollection.size(); ++i ) std::cout << primaryCollection[i];
}
int main()
{
    CreateReport mime;
    mime.load();
}

第二个版本将 `Record*` 用于 `std::vector primaryCollection`。

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

    class Record{
      public:
          Record(int = 0, string = "", string = "");
          ~Record()=default;
    friend  std::ostream& operator<<(std::ostream&, const Record&);
        private:
           int year;
           string province;
           string degree;
    };
// **** output overload for Record ***********
    std::ostream& operator<<(std::ostream& os, const Record& rd)
    {
        os << "year = " << rd.year << "  prov = " << rd.province << "  degree = " << rd.degree << std::endl;
        return os;
    }
// ****** end of output overload **************
Record::Record(int i1, string s1, string s2) : year(i1), province(s1), degree(s2){}
//end of Record.cc
//
class CreateReport{
  public:
    CreateReport() = default;
    void load();

  protected:
    static vector<Record*> primaryCollection; //STL vector of record pointers
};
//***************** you need this line ********************
std::vector<Record*> CreateReport::primaryCollection;
//*********************************************************
void CreateReport::load(){
    int year;
    string province, degree;

    ifstream infile("graduate.dat", ios::in);

    if (!infile) {
        cout << "Error: could not open file" << endl;
        exit(1);
    }

    while (infile >> year >> province >> degree) {
            Record *a = new Record(year, province, degree);
        primaryCollection.push_back( a );
    }

    cout<<endl<<"List of Records:"<<endl;
    for (int i = 0; i<primaryCollection.size(); ++i ) std::cout << *primaryCollection[i];
}
int main()
{
    CreateReport mime;
    mime.load();
}