簡體   English   中英

如何實現一個 class 模板,為其派生類提供跟蹤其實例的功能?

[英]How to implement a class template that provides functionality to its derived classes to track their instances?

我正在嘗試創建一個抽象的 class 模板(InstanceTracker),如果類需要對其所有實例執行操作的功能,則可以從該模板繼承。 class 包含指向“T”的指針的 static 向量,每次運行 InstanceTracker 構造函數時,我都會推回指向該向量的新指針。 我通過一個返回“T*”的純虛擬 getDerivedPtr() 方法來執行此操作,從 InstanceTracker 派生的每個 class 都必須通過return this; . 不過,您可能已經看到出了什么問題。 您永遠不能從基本構造函數調用純虛擬 function - 因為它還不存在。 如何為我的 InstanceTracker class 找到解決此問題的方法? 這是 class 的代碼:

#pragma once
#include <vector>

template <typename T>
class InstanceTracker
{
public:
    InstanceTracker() noexcept
    {
        allInstances_.push_back(getDerivedPtr());
    }
    InstanceTracker(const InstanceTracker& source) noexcept
        : InstanceTracker()
    {
    }
    InstanceTracker(const InstanceTracker&& source) noexcept
        : InstanceTracker()
    {
    }
    virtual ~InstanceTracker() noexcept
    {
        auto it = std::find(allInstances_.begin(), allInstances_.end(), this);
        int index = it - allInstances_.begin();
        allInstances_.erase(allInstances_.begin() + index);
    }
    virtual T* getDerivedPtr() = 0;
protected:
    static std::vector<T*> allInstances_;
};

如果您想嘗試運行代碼並查看為什么它現在不起作用,這里有一個簡單的 class 繼承自 InstanceTracker:

class Derived1 : public InstanceTracker
{
public:
    Derived1* getDerivedPtr() override
    {
        return this;
    }
};

你可能最好使用組合而不是 inheritance,但我認為你有充分的理由更喜歡 inheritance。

困難在於,當運行基本 class 構造函數時, this指針僅是指向基本 class 實例的指針。 派生實例甚至還沒有退出。 (同樣,在銷毀時,object 的派生部分已經未初始化)。 因此,如果您調用虛擬方法,您將獲得基本的 class 實現,而不是派生類的實現。 在您的情況下,基本 class 實現甚至不存在,所以您被卡住了。

可能可以將基類的this指針轉換為指向派生 class 的指針,但這不能保證有效,並且可能涉及未定義的行為。

解決此問題的一種方法是存儲指向基類型 ( InstanceTracker * ) 的指針,而不是指向派生類型的指針。 然后你的getDerivedPtr方法不需要是虛擬的,它可以在安全的情況下進行強制轉換。

template <typename T>
class InstanceTracker {
    public:
        InstanceTracker() noexcept {
            allInstances_.push_back(this);
        }

        // other constructors elided for space

        virtual ~InstanceTracker() noexcept {
            std::erase(
                std::remove(allInstances_.begin(), allInstances_.end(), 
                            this),
                allInstances.end());
        }

        T* getDerivedPtr() {
            return static_cast<T*>(this);  // downcast
        }

    protected:
        // allInstances_ stores base class pointers
        static std::vector<InstanceTracker*> allInstances_;
};

筆記:

  • 如果您使用 RTTI,運行時類型識別,您可以使用dynamic_cast而不是static_cast 您不應該使用reinterpret_cast ,因為編譯器可能需要調整基指針作為轉換的一部分。

  • 如果您將派生類型的實例創建為const ,您可能會遇到問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM