我写了一个程序,它使用虚函数来实现多态性。我有一个主要的 User 类,它盲目地调用它认为是通用对象的方法(尽管它们实际上应该是专门的)。这些对象来自覆盖其基类中的纯虚函数的类。以下改编代码应演示我的设置:
BaseConfig.h 中的泛型类(BaseConfig):
class BaseConfig {
public:
...
virtual void display() const = 0;
...
}
SpecialConfig.h 中上述泛型类 (SpecialConfig) 的专用版本:
class SpecialConfig : public BaseConfig {
public:
...
void display() const;
...
}
SpecialConfig.cpp中上述特化类的实现:
...
void SpecialConfig::display() const {
// print some text
}
...
现在,当我创建 BaseConfig 指针并将其设置为 SpecialConfig 对象的地址时,调用 display() 会按预期调用 SpecialConfig 类的 display() 函数。但是,由于某些原因,在 BaseConfig 队列中返回 SpecialConfig 对象后,在以下代码片段中,事情与我所期望的有所不同,对它们调用 display() 函数不再命中 SpecialConfig 中的 display() 函数而是尝试使用 BaseConfig 中的 display() 函数,导致程序退出。
这是一个用于生成配置排列的通用类。我们将在 BaseRuleSet.h 中将其称为 BaseRuleSet:
class BaseRuleSet {
public:
...
virtual queue<BaseConfig *> getValidChildConfigurations(BaseConfig * c) const = 0;
...
}
它的 getValidChildConfigurations 函数将在专门的 RuleSet 类中被覆盖,如 SpecialRuleSet.h 中的类 SpecialRuleSet 所示:
class SpecialRuleSet : public BaseRuleSet {
public:
...
queue<BaseConfig *> getValidChildConfigurations(BaseConfig * c) const;
}
SpecialRuleSet.cpp中上述类的实现:
...
queue<BaseConfig *> SpecialRuleSet::getValidChildConfigurations(BaseConfig * c) const {
queue<BaseConfig *> validChildConfigurations;
BaseConfig * baseConfigA;
BaseConfig * baseConfigB;
SpecialConfig specialConfigA;
SpecialConfig specialConfigB;
baseConfigA = &specialConfigA;
baseConfigB = &specialConfigB;
validChildConfigurations.push(baseConfigA);
validChildConfigurations.push(baseConfigB);
// validChildConfigurations.front()->display() works correctly here
return validChildConfigurations;
}
...
如上面的评论所示,此时多态性仍在正常工作,因为专用显示功能仍在使用中。然而,在最后一个代码片段(如下所示)中,一切都崩溃了。这是 User.cpp 中的用户类:
...
void User::doStuff() {
BaseRuleSet * baseRuleSet;
SpecialRuleSet specialRuleSet;
baseRuleSet = &specialRuleSet;
BaseConfig * currentConfig;
/*
SpecialConfig specialConfig;
currentConfig = &specialConfig;
currentConfig->display(); // this works
*/
queue<BaseConfig *> childConfigurations = ruleSet->getValidChildConfigurations(currentConfig);
childConfigurations.front()->display(); // this does not work
}
如上例中的最后一条评论所示,对 display() 的最后一次调用实际上尝试使用 BaseConfig 中的纯虚函数,而不是 SpecialConfig 中已实现的专用版本。
我的想法是在 C++ 中存在我不知道的限制或不同的处理方式,或者我的实现中存在错误。谁能帮我澄清一下?
谢谢。
最佳答案
问题与多态性无关。您的实际问题如下。
BaseConfig * baseConfigA; // Okay.
SpecialConfig specialConfigA; // Fair enough
baseConfigA = &specialConfigA; // Hmm, getting the address of a local variable?
validChildConfigurations.push(baseConfigA); // This should be okay as long as
// you don't return that queue...
return validChildConfigurations; // Oh dear.
你看,在 C++ 中,局部变量与其作用域一样长。 specialConfigA
对象将在 getValidChildConfigurations
返回后立即被销毁,之后您存储在队列中的指针指向...未定义的东西。因此,当您尝试通过它调用方法时,您会得到未定义的行为,这在您的情况下是崩溃。
解决方案是动态分配SpecialConfig
对象:
BaseConfig * baseConfigA = new SpecialConfig;
这意味着对象只会在您调用delete
时被销毁。这既是一件好事也是一件坏事:它不会再超出范围,但是当你完成时你一定不要忘记使用 delete
,否则内存会泄漏。一种解决方案是使用智能指针为您执行 delete
。 C++11 有用于此目的的 std::shared_ptr
类。如果你仍然停留在 C++03 中,你可以使用 boost::shared_ptr
.
如果您不能或不想使用智能指针,请记住 queue
的构造函数不会对其内容调用 delete
,因此您必须在某一时刻遍历它并删除
所有内容。
关于c++ - 多态实现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8885151/