使用具有抽象基础 class 指针的映射并调用派生的 class 函数

Using a map that has a abstract base class pointer and calling a derived class function

我在网上搜索过,找不到解决我的问题的办法希望你能帮上忙。

所以我构建了一个抽象基础 class 并有两个派生的 class 代表不同的实验。 (一个其实是我的baseclass的一个derived derivedclass)然后我在一个单独的头文件中制作了一个这样的map来存储不同类型的实验。

//Map class template to store name of experiment and the experiment within a project
typedef map <string, baseData <double>*> ExpContainer;

void search(string searchName, ExpContainer exps) {
    ExpContainer::iterator Iter;
    Iter = exps.find(searchName); //finds the entry corresponding to searchName and returns the iterator
    if (Iter != exps.end()) { //need this as if entry is not found, the return will be end iter.
        cout << "Found the experiment " << Iter->first << "." << endl;
        Iter->second->print();
    }
    else {

        cout << "Sorry, experiment " << searchName << " is not found" << endl;
    }

}

每个实验类型的 print() 函数都不同,我知道有一个称为切片的问题,所以我确保 print() 在基础 class 中是虚拟的。这是我的基地 class:

namespace mynmsp {

//base class of data can be measurements or errors
template < class T> class baseData { 

public:
    virtual void print() =0;
    virtual ~baseData() {
        cout << "Destructor called for the base class." << endl;
    }
};
}

然后在我的 main.cpp 中构建了不同类型的实验,我想打印它们。每个实验 class 都有不同的打印函数实现,这些打印函数会覆盖基础 class 的打印函数,例如:

void print(){ //do something }; 

在我的 main.cpp 中,我将地图定义为:

ExpContainer project;

在构建每个实验后,我要求用户提供实验名称 (expName) 并插入到项目中:

project[expName] =  &expC;

我认为插入没问题,因为我测试了项目的大小并且它是正确的。 但是,当我的搜索函数被这样调用时发生了运行时错误:

search(name, project);

不知道是切片有问题还是我的指针有问题? 我试图在每个派生的 class 中使 print() 成为虚函数,但这似乎也不起作用。

很抱歉问题很长,请帮忙!

编辑:我在一个 do while 循环中构建了我的实验,而项目是在外部声明的。整个代码很长,但它的基础是这样的:

string repeatstr; //user input whether to repeat do while loop or not
bool repeat = true; //condition for staying inside do while loop
ExpContainer project; //declared project to store experiments

do {
    string expName;
    string ans1; //character to store user input
    cout << "What is the name of your experiment? " << endl;
    cin >> expName;
    cout << "Is this a experiment C ? (y/n)" << endl;
    cin >> ans1; 
       if(ans1 =="y"){ 
           //call the constructor for expC
           project[expName] = &expC;
        }else {
           //call the constructor for expB 
          project[expName] = &expB;
        }

    cout << "Do you want to enter another experiment?  (y/n)" << endl;
    cin >> repeatstr;
    if (repeatstr == "n") { repeat = false;  }

}while (repeat); //loop over this do-while loop while repeat is true

    cout << "There are " << project.size() << " in this database." << endl;

    //to retrieve info from a certain experiment
    string input, name;
    cout << "Would you like to retrieve any experiments (y/n)? " << endl;
    input = EitherInput("y", "n");
    if (input == "y") {
        cout << "Please enter the name of the experiment you want to retrieve: " << endl;
        cin >> name;
        search(name, project); //code breaks down here!
    }

您正在保存指向已销毁对象的指针。您可以检查地图中的地址,很可能它们是相同的。您应该将实验对象存储在动态内存中

if(ans1 =="y")
{ 
    project[expName] = new expC();
} // Scope ends here and all variable created in it will be destroyed.
else 
{
  project[expName] = new expB();
} // Scope ends here and all variable created in it will be destroyed.

使用完它们后,您需要对每个指针调用 delete 以避免内存泄漏。您还需要检查地图中的项目是否已经存在,否则您将丢失指向已分配内存的指针,这将自动导致内存泄漏。

我建议您使用 std::share_ptr< baseData<double> > 而不是裸 baseData<double>*Here 您可以阅读更多相关信息。并考虑使用 typedef 以获得更清晰的语法。


P.S。 函数

void search(string searchName, ExpContainer exps)

会将整个地图复制到它的正文中。使用常量引用代替

void search(string searchName, const ExpContainer& exps)

但是你还需要将函数 print 声明为 const:

virtual void print() const = 0;

并用 const 修饰符覆盖它:

virtual void print() const override;

并使用常量迭代器ExpContainer::const_iterator Iter