从祖先的方法和构造函数调用后代的方法
Posted
技术标签:
【中文标题】从祖先的方法和构造函数调用后代的方法【英文标题】:Call descendant's method from ancestor's methods and constructor 【发布时间】:2016-09-26 19:09:32 【问题描述】:接下来的代码展示了类参数包装器,它允许通过 getter 和 setter 访问底层类。简化版:
template<typename T>
class Parameter
public:
typedef T value_type;
typedef Parameter<T> Type;
protected:
T value_;
public:
Parameter() this->value_ = this->default_value();
Parameter(T&& val) this->set(std::forward<T>(val));
Parameter(const T& val) this->set(std::forward<T>(val));
virtual ~Parameter() ;
// Get
T& get() return this->value_/*this->getter()*/;
operator T&() return this->get();
// Set
Type& set(T&& val)
std::cout << "T&& setter called with " << val << std::endl;
value_ = this->setter(std::forward<T>(val));
return *this;
Type& set(const T& val)
std::cout << "constT& setter called with " << val << std::endl;
value_ = this->setter(std::forward<const T>(val));
return *this;
Type& operator=(T const& val) return this->set(val);
Type& operator=(T&& val) return this->set(val);
virtual T setter(T const& val) return val;
virtual const T& default_value()
static const T default_value_;
return default_value_;
;
;
使用:
int main()
struct IncrementorPar : Parameter<int>
using Parameter::Parameter; //todo HIDE
using Parameter::operator=; //todo HIDE
virtual int setter(int const& val) return val + 1;
virtual const int& default_value() return -1; ;
in1(1), in2 = 2, int0;
//assert(int0==int0.default_value()); //FAIL
//assert(int0==-1); //FAIL
//assert(in1 == 2); //FAIL
//assert(in2 == 3); //FAIL
auto *pi1 = new IncrementorPar(2);
//assert(*pi1==3); //FAIL
pi1->set(2);
assert(*pi1==3);
*pi1 = 33;
怎么可能从祖先的构造函数中调用后代的方法setter()
和default_value()
?
如何隐藏using
的?
【问题讨论】:
【参考方案1】:并不是一个真正优雅的解决方案,但是...
您可以使用init()
函数推迟value_
的初始化。
类似
template<typename T>
class Parameter
private:
bool toInit true ;
bool initWithVal;
T valInit;
void init ()
if ( initWithVal )
this->set(valInit);
else
value_ = this->default_value();
toInit = false;
public:
typedef T value_type;
typedef Parameter<T> Type;
protected:
T value_;
public:
Parameter() : initWithValfalse
Parameter(T&& val) : initWithValtrue, valInitstd::move(val)
Parameter(const T& val) this->set(std::forward<T>(val));
virtual ~Parameter() ;
// Get
T& get() if ( toInit ) init(); return this->value_/*this->getter()*/;
operator T&() return this->get();
// Set
Type& set(T&& val)
toInit = false;
std::cout << "T&& setter called with " << val << std::endl;
value_ = this->setter(std::forward<T>(val));
return *this;
Type& set(const T& val)
toInit = false;
std::cout << "constT& setter called with " << val << std::endl;
value_ = this->setter(std::forward<const T>(val));
return *this;
Type& operator=(T const& val) return this->set(val);
Type& operator=(T&& val) return this->set(val);
virtual T setter(T const& val) return val;
virtual const T& default_value()
std::cout << "base default value\n";
static const T default_value_;
return default_value_;
;
;
【讨论】:
【参考方案2】:说明
如果不重写每个派生类的构造函数,就不可能从祖先调用后代的方法,因为在构造过程中,vtable
仅按照构造函数调用的顺序(其中我们记得,是基础 -> 最衍生)。
摘自forum:
我有一个类,它从它的构造函数中调用一个虚方法
Init()
。 在后代中,我覆盖了这个虚拟方法Init()
。这个想法是 每当我创建后代时,我希望后代的Init()
是 叫,不是祖宗!而且我不想覆盖构造函数 那是因为我必须重写每个后代的构造函数 然后。这怎么可能?
回答
不重写每个派生类的构造函数是不可能的, 在施工期间,
vtable
仅提供有关 到目前为止构造的类,按照构造函数调用的顺序(正如我们 回想一下,是基础 -> 最衍生的)。所以当ClassA
的构造函数被调用时, 尽管它是ClassB
的实例,但虚函数机制将 只能在之后访问ClassB
对ClassA
函数的覆盖ClassA
的构造函数已经执行完毕,所以任何时候你调用一个 virtual 将调用来自ClassA::ClassA()
、ClassA::Init()
的函数。 ——丹
解决方案
按照@max66 的建议使用init guides-variables,或类似的东西。
【讨论】:
以上是关于从祖先的方法和构造函数调用后代的方法的主要内容,如果未能解决你的问题,请参考以下文章