从祖先的方法和构造函数中调用后代的方法

时间:2016-09-26 19:09:33

标签: c++ c++11 inheritance parameters constructor

下一个代码提供了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()

2 个答案:

答案 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建议或类似的东西。