我想要做的是让现有层次结构中的某些类能够通过成员函数重新初始化其中一个基类。我知道如果从绿地开始,这将是一个糟糕的设计决定。我想知道是否有任何技巧让它以任何方式发挥作用。
这是我天真的尝试:
class Base {
const int i_;
std::unique_ptr<int> ui_;
public:
Base() :i_{ 0 }{}
Base(int i) :i_{ i }{}
Base(Base && other) :i_{ other.i_ }, ui_{ std::move(other.ui_) }{}
virtual void f(){
std::cout << "Base f";
}
virtual ~Base(){
std::cout << "Base dtor";
}
};
class Derived : public Base {
public:
virtual void f(){
std::cout << "Derived f";
}
void reinitializeBase(Base && other){
static_cast<Base*>(this)->Base::~Base(); //only call bases dtor
new (static_cast<Base*>(this)) Base(std::move(other));
}
virtual ~Derived(){
std::cout << "Derived dtor";
}
};
问题显然是基类构造函数破坏了指向vtable的指针(使其指向base而不是派生)。
我知道这样做的“正确”方法是通过派生类的构造函数传递base构造函数的参数。这是不可能的,因为派生类是由我无法修改的工厂创建的。我也可以在不重建基础的情况下移动唯一指针的内容但是我仍然无法修改const int
编辑: 抱歉,我忘了提到我也无法修改基类。
答案 0 :(得分:1)
收到新信息后: 编写一个包含成员de'Base'类的Wrapper类。
包装器可以使用set / get函数来访问/更改内部的“Base”类。
答案 1 :(得分:1)
不,你不能。
除了修改base.h
以便以ABI兼容方式进行私人使用并使base
表现得更好之外,没有任何黑客可以做得更安全。这需要您的编译器ABI以及您的代码将在其下编译的所有未来ABI的知识,这对于任何非平凡的项目都是不可能的。
如果你的生活依赖于它,你可以这样做:但是可靠地做到这一点需要不断对抗ABI变化。在实践中,我会更改base
,或pImpl
隐藏base
,或停止使用base
。
答案 2 :(得分:0)
我会在基类上创建一个函数Reset
,这样你可以更好地控制你想要重新初始化的内容