我知道在超類ctor完成之前,子類(和vtable)還沒有完成。但是,我有一種情況,從邏輯上講,我必須能夠更改超類的初始化,我正在嘗試弄清楚如何做到這一點。
這是一個簡化的示例:
class Window {
std::thread uiThread;
void uiThreadProc(){
try {
UIInit();
NotifyOtherThreadThatUIInitFinished();
} catch(...){
UIClean();
throw; // actually using an exception_ptr but it's irrelevant here
}
EventLoop();
UICleanup();
}
virtual void UIInit();
virtual void UICleanup();
Super(){
CreateUIThread();
WaitForUIThreadToFinishUIInit();
}
~Super(){
SendQuitEventToUIThread();
WaitForUIThreadToFinish();
}
}
class Overlay : public Window {
Overlay(){
// can't do stuff before UIInit because Window ctor returns when UIInit finishes
}
void UIInit() override {
// won't be called because UIInit is called before Window ctor returns
}
void UIClean() override {
// won't get called if UIInit throws
}
~Overlay(){}
}
目前,我試圖通過將 ctors 設為私有并將邏輯移動到在 ctors 之后呼叫的 Init 方法來使其作業,如下所示:
class Window {
static std::shared_ptr<Window> Create(){
auto window = std::make_shared<Window>();
window->Init();
return window;
}
virtual void Init() { /* actual ctor content here */ }
virtual void Cleanup() { /* actual dtor content here */}
bool cleanupCalled = false;
~Window(){
if(!cleanupCalled){
cleanupCalled = true; // with mutex and locks...
Cleanup();
}
}
}
class Overlay : public Window {
// same as above, but now overriding Init() and Cleanup()...
}
我認為這會奏效,但感覺超級笨拙和令人費解。
而且我不明白為什么從設計的角度來看為什么會這樣,為什么ctors不先創建完整的vtable,然后呼叫ctors的層次結構?vtable 不依賴于成員初始化,所以它不會破壞首先要做的事情,對嗎?
這不是繼承的一個很好的用途嗎?
I need to be able to override UIInit because some things must run on the UI thread. I could send it as functions/events and the EventLoop would execute that, but that would seriously break the logic of "when ctor finishes, the object is fully initialized", or if it absolutely has to run before the EventLoop. I could make my own thread event handling class, but that simply seems wrong for such a trivial case.
Any architectural suggestions are very welcome.
uj5u.com熱心網友回復:
這可以通過使用組合而不是繼承來解決。
此外,UIInit()并且UICleanup()正在乞求由 RAII 驅動。我們可以通過Overlay分成兩種型別來做到這一點:配置,意味著存在于主執行緒中,以及“運行時”子型別,可以存在于視窗的執行緒中。
#include <concepts>
#include <utility>
// Ignore these concepts pre-c 20
template<typename T, typename Owner>
concept WindowControllerRuntime = std::constructible_from<T, Owner*> &&
requires(T r) {
// Use this in lieu of pure virtual functions
{r.update()};
};
template<typename T>
concept WindowController = WindowControllerRuntime<typename T::Runtime, T>;
class Window {
public:
virtual ~Window() = default;
};
// pre-c 20: use template<typename ControllerT> instead
template<WindowController ControllerT>
class WindowWithController : public Window {
ControllerT controller_;
public:
WindowWithController(ControllerT controller)
: controller_(std::move(controller)) {
CreateUIThread();
WaitForUIThreadToFinishUIInit();
}
~WindowWithController() {
SendQuitEventToUIThread();
WaitForUIThreadToFinish();
}
void uiThreadProc(){
typename ControllerT::Runtime runtime(&controller_);
NotifyOtherThreadThatUIInitFinished();
EventLoop();
UICleanup();
}
private:
void SendQuitEventToUIThread();
void WaitForUIThreadToFinish();
void CreateUIThread();
void WaitForUIThreadToFinishUIInit();
void NotifyOtherThreadThatUIInitFinished();
void EventLoop();
void UICleanup();
};
// Usage example
#include <memory>
class Overlay {
public:
struct Runtime {
Runtime(Overlay* owner) {} // UIInit
~Runtime() {} //UIClean
void update() {}
};
};
int main() {
std::unique_ptr<Window> w = std::make_unique<WindowWithController<Overlay>>(Overlay{});
}
uj5u.com熱心網友回復:
我最終使用的是這個:
std::shared_ptr<Overlay> Overlay::Create() {
std::shared_ptr<Overlay> ptr(new Overlay(), [](Overlay* toDelete) {
toDelete->Cleanup();
delete toDelete;
});
ptr->Init();
return ptr;
}
但這有它的局限性:
- 我不能在堆疊上分配的疊加(因為那樣我會打電話
Init和Cleanup手動,以及整點是自動執行)。 - 我必須
Create在 Window 的每個子類中復制粘貼該方法。也許有一種方法可以使用模板自動執行此操作,但如果不將整個類設為模板,我就無法做到這一點。
我還不會接受我的答案,也許有人會有更好的解決方案。
意見:我是 C 的初學者,但老實說,在我看來,無法在建構式/解構式中呼叫虛方法似乎是一個巨大的設計缺陷。其他語言做得很好(咳嗽,Java,咳嗽)。而且我不明白為什么它不適用于堆疊分配和堆分配。你可以手動(真正的ctor,假的ctor,dostuff,假的dtor,dtor)所以編譯器可以做同樣的事情(分配記憶體,填充vtable,基的ctor,子的ctor,做東西,子的dtor ,基的 dtor,釋放記憶體)。這樣一來,基地就可以讓潛艇有機會在基地的 ctor/dtor 之前/之后做一些事情。但無論如何,也許我遺漏了一些技術原因。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/350968.html
標籤:c inheritance architecture vtable
上一篇:派生類的屬性為空
下一篇:錯誤列計數與第1行的值計數不匹配
