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

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

本文关键字:映射 调用 派生 类函数 指针 抽象 基类      更新时间:2023-10-16

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

因此,我构建了一个抽象基类,并有两个派生类来表示不同的实验。(其中一个实际上是我基类的派生类)我在一个单独的头文件中制作了一个映射,以存储不同类型的实验。

//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()在基类中是虚拟的。这是我的基类:

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中,我构建了不同类型的实验,我想打印它们。每个实验类都有不同的打印函数实现,该函数覆盖基类中的打印函数,如:

void print(){ //do something }; 

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

ExpContainer project;

在我构建了每个实验之后,我向用户询问了实验的名称(expName),并插入到项目中,如下所示:

project[expName] =  &expC;

我认为插入是好的,因为我测试了项目的大小,它是正确的。然而,当我的搜索函数被这样调用时,出现了一个运行时错误:

search(name, project);

我不知道是切片有问题还是我的指针有问题?我试图在每个派生类中使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>*。在这里你可以阅读更多关于它的内容。也可以考虑使用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