下一个代码提供了class-parameter-wrapper,它允许通过getter和setter访问底层类。简化版:
Person
使用:
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()
?
答案 0 :(得分:1)
不是一个优雅的解决方案,但......
您可以使用value_
函数推迟init()
的初始化。
像
这样的东西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() : initWithVal{false} { }
Parameter(T&& val) : initWithVal{true}, valInit{std::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_;
};
};
答案 1 :(得分:0)
不能从祖先的方法调用后代的方法,而不会覆盖每个派生类的构造函数,因为在构造过程中,vtable
只有构造函数调用的顺序,只有到目前为止构造的类的信息。 (我们记得,它是基础 - >大多数派生的。)
摘自forum:
我有一个类,它从构造函数中调用一个虚方法
Init()
。 在后代中,我覆盖了这个虚方法Init()
。这个想法是 每当我创建一个后代时,我都想要后代的Init()
叫,不是祖先!而且我不想覆盖构造函数 因为我必须覆盖每个后代的构造函数 然后。这怎么可能?
答案
如果没有覆盖每个派生类的构造函数,那是不可能的, 在施工期间,
vtable
只有关于的信息 构造函数调用的顺序是如此构造的类(正如我们所做的那样) 回想一下,是基础 - &gt;最衍生的)。所以当ClassA
的构造函数被调用时, 尽管它是ClassB
的实例,但虚函数机制将会 之后只能访问ClassB
的{{1}}覆盖的功能ClassA
的构造函数已经完成执行,因此任何时候调用虚拟 来自ClassA
的函数,ClassA::ClassA()
将被调用 - 丹
使用init guide-variables作为@ max66建议或类似的东西。