构造函数用例中的虚函数调用
virtual function call in constructor use case
所以我从各种在线资源中知道,从构造函数中调用虚函数通常是不行的。 我意识到这里的问题是基类将首先构造,C++将首先调用函数的基类版本。 但是,我有一个独特的用例,可能可以接受。 我将不胜感激一些评论。 考虑这种情况。
class Base
{
public:
Base(string data)
{
Parse(data);
}
~Base(){}
private:
virtual Parse(string data);
}
class Derived : public Base
{
public:
Derived(string data)
{
Parse(data);
}
~Derived();
private:
Parse(string data);
}
假设我有一个这样的设置,每个派生类的预期行为是:
- 在基类中调用 Parse 以解析出所有这些输入字符串应该共有的内容。 派生
- 分析应获取特定于派生类的数据。
在这种情况下,在构造函数中使用虚函数是否有意义? 还是我被迫公开"解析"并在每次构造此类时调用它? 还是有其他建议。
我希望这是有道理的,请原谅上面的任何语法错误,我只是想表达一个大致的想法。
还是我被迫公开"解析"并在每次构造此类时调用它?
实际上,在这种情况下,由于您想避免多态行为,我不明白为什么您必须将Parse
设置为虚拟方法,甚至是类的非静态方法,因为它不会修改类本身的任何数据成员......例如,您可以将Parse
作为私有static
方法,然后只需在每个对象的构造函数中调用ClassType::Parse()
,您将获得相同的功能。
在构造函数中使用虚函数绝对没有错,只要它适合你。重要的是要记住,从构造函数调用虚函数的多态行为始终仅限于整个层次结构中已经构造的子集。(类似的规则适用于析构函数)。
如果这种受限制的虚拟行为适合您的目的,他们会通过各种方式使用它。
你一定指的是"no-no"参数是一个众所周知的假参数,它基于用户期望调用[尚未构造的]派生类函数的人为前提。为什么有些人把这个发明的错误前提转化为不应该从构造函数调用虚函数的结论,这超出了我的理解。我还没有看到可信的解释。
解决方案非常简单:
class Base
{
public:
Base(string data)
{
Parse(data);
}
~Base(){}
private:
void Parse(string data);
}
class Derived : public Base
{
public:
Derived(string data)
{
ParseMore(data);
}
~Derived();
private:
void ParseMore(string data);
}
构造Derived
时,在输入 Derived
的构造函数之前调用 Base
的构造函数。因此,在 Base 中进行的分析将完成,您可以在派生构造函数中完成分析。
不要从构造函数调用虚函数。您不会获得多态行为,因为将使用基类虚拟表。
如果你不需要多态行为 - 不要使函数成为虚拟
最简单的解决方案是使用策略模式:定义一个抽象基类Parser
,具有纯虚函数parse
,以及让派生类传递指向其解析器实例的指针到基类构造函数;即:
class Base
{
protected:
class Parser
{
public:
virtual ~Parser() {} // Probably not necessary, since no
// one is going to dynamically
// allocate any of these, but better
// safe than sorry.
virtual void parse( std::string const& data ) const = 0;
};
Base( Parser const& derivedClassParser, std::string const& data )
{
derivedClassParser.parse( data );
}
public:
// ...
};
每个派生类都将定义其解析器,派生自 Base::Parser
,定义它的静态实例,并传递此静态实例向下到基类。
还有另一种可能性;如果您有对象的临时实例,但如果某些原因您无法使用上述模式。 基本上,您定义一个在其析构函数中调用虚函数的特殊类,以及具有从 std::string
的隐式转换(也可能是从 char
const*
进行隐式转换,以支持传递字符串文本),并声明您的构造函数来获取此类的实例;例如:
class Base
{
public:
class CallVirtual
{
std::string myData;
mutable Base* myOwner;
friend class Base;
public:
CallVirtual( std::string const& data )
: myData( data )
, myOwner( NULL )
{
}
~CallVirtual()
{
if ( myOwner != NULL ) {
myOwner->Parse( myData );
}
}
};
Base( CallVirtual const& dataArg )
{
dataArg.myOwner = this;
// ...
}
virtual void Parse( std::string const& data ) ...
};
派生类还应将CallVirtual const&
作为参数。然后,在创建派生类的实例时:
Base* p = new Derived( someString );
,字符串自动转换为临时CallVirtual
,将在完整表达式的末尾调用其析构函数。
- 在c++中使用向量时,如何调用构造函数和析构函数
- C++:考虑但不调用构造函数的特殊性
- 对象实例化调用构造函数的次数太多
- 我使用向量来创建类对象列表.初始化向量时如何使用参数调用构造函数?
- C ++:通过大括号调用构造函数?
- 不能调用构造函数
- 赋值 boost::intrusive_ptr 而不调用构造函数?
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- 当我尝试从成员函数调用构造函数时,为什么IDE会发出警告
- 从复制构造函数调用构造函数
- 从同一类的另一个构造函数调用构造函数
- 从另一个成员函数/构造函数调用C++构造函数是否执行初始值设定项列表
- 通过引用从函数调用C++构造函数
- 从不同类的构造函数调用构造函数
- 错误:没有匹配的函数调用'构造函数'注意:候选函数是:
- 从构造函数调用构造函数
- 用数组初始化从另一个构造函数调用c++构造函数
- 从成员函数调用构造函数
- 在c++中从另一个构造函数调用构造函数时出错
- 可以从静态函数调用构造函数