跟踪对象类型
Keep track of object types
我要实现的目标是跟踪我们创建的从基类继承的对象类型。如果类从基类继承但不是在对象中实例化的,那么我对跟踪该类别不感兴趣(可以包括该条件,具体取决于实现是否易于实现)
)虚拟示例:
template <typename T>
class Person
{
public:
Person() {
T* x;
container.push_back(x);
}
virtual ~Person() {}
private:
static heterogeneous_container container;
};
class Employee : public Person <Employee>
{
};
class Employee2 : public Employee
{
};
另外,我希望这为链接的继承工作。当我实例化员工2时,基类人员可能会在容器中添加一个员工2型指针吗?
至于异质容器,我认为可以使用链接
我认为您想要的更像是:
class Person
{
public:
Person() {
objects.push_back(this);
}
virtual ~Person() {
objects.erase(this);
}
private:
static std::set<const Person*> objects;
};
class Employee : public Person
{
};
class Employee2 : public Employee
{
};
使用这种方法,您可以查询容器中每个指针指向的最衍生对象的动态类型。
请注意,objects
集必须包含指针,不是每个对象的type_info。问题在于,Employee2
对象的Person
子对象的构造函数内部,最衍生的*this
类型将是Person
,而不是Employee2
(直到执行输入Employee2
构造函数,它才会成为Employee2
)。
或多或少,我有这样的地方:
#include <iostream>
#include <functional>
#include <vector>
struct ClassEntry {
size_t id = 0;
const char* label;
};
class BaseClass {
public:
protected:
static void RegisterType(size_t id, const char * label) {
ClassEntry entry;
entry.id = id;
entry.label = label;
mRegisteredTypes.emplace_back(entry);
std::cout << "Registered type " << id << " label " << label << std::endl;
}
static size_t createId() {
static size_t id = 0;
return id++;
}
static std::vector<ClassEntry> mRegisteredTypes;
};
std::vector<ClassEntry> BaseClass::mRegisteredTypes;
class OneTimeCall {
public:
OneTimeCall(std::function<void(void)>&& func) {
func();
}
virtual ~OneTimeCall() {
}
};
template<typename T>
class MyClass : public BaseClass {
public:
MyClass() {
static OneTimeCall one_time {
[this]{
BaseClass::RegisterType(GetId(), T::GetType());
}
};
}
private:
protected:
static size_t GetId() {
static size_t id = BaseClass::createId();
return id;
}
};
class A : public MyClass<A> {
public:
A() {
}
static const char *GetType() {
return "ClassA";
}
};
class B : public MyClass<B> {
public:
B() {
}
static const char *GetType() {
return "ClassB";
}
};
int main() {
A a;
B b;
A a2;
B b2;
return 0;
}
输出为:
Registered type 0 label ClassA
Registered type 1 label ClassB
主要思想是仅一次在构造中使用CRTP和静态初始化。它在Linux中无问题,在Windows编译器上静态基本ID是每个DLL上的新事物,因此您需要对外部库中使用一些调整。
使用这种方法,您不需要任何外部库,并且可以在没有RTTI的情况下进行编译。
对于继承您可以创建一个新类:
template<typename Current, typename Base>
class Mix : public MyClass<Current>, public Base {};
因此,如果将"类型C"作为当前类型(CRTP)和A型AS AS基类操作。
class C : public Mix<C, A> {
public:
C() {
}
static const char *GetType() {
return "ClassC";
}
};
使用此方法,如果您先前已经注册了" A",它将不会再次注册,如果您没有" A",则将在" C"之后注册。
跟踪对象的一种方法是将它们存储一个侵入性列表,并将链接节点嵌入到对象中。这为跟踪器操作提供了noexcept
的保证,并且在将元素插入跟踪器容器中时不需要额外的内存分配,以每个跟踪对象的嵌入式列表节点(两个指针)的价格:
#include <iostream>
#include <boost/intrusive/list.hpp>
namespace bi = boost::intrusive;
template<class T>
class Tracker : public bi::list_base_hook<bi::link_mode<bi::auto_unlink>>
{
protected:
static bi::list<Tracker, bi::constant_time_size<false>> objects_;
Tracker() noexcept { objects_.push_back(*this); }
Tracker(Tracker const&) noexcept { objects_.push_back(*this); }
public:
static auto count() noexcept { return objects_.size(); }
};
template<class T>
bi::list<Tracker<T>, bi::constant_time_size<false>> Tracker<T>::objects_;
struct Employee : Tracker<Employee> {};
struct Employee2 : Employee {};
int main() {
std::cout << Tracker<Employee>::count() << 'n';
{
Employee e0;
Employee2 e1;
std::cout << Tracker<Employee>::count() << 'n';
}
std::cout << Tracker<Employee>::count() << 'n';
}
输出:
0
2
0
Tracker
没有升压库:
struct AutoListNode {
AutoListNode *next_ = this, *prev_ = this;
AutoListNode() noexcept = default;
AutoListNode(AutoListNode const&) = delete;
AutoListNode& operator=(AutoListNode const&) = delete;
~AutoListNode() noexcept { this->erase(); }
void push_back(AutoListNode* node) noexcept {
auto prev = prev_;
node->prev_ = prev;
node->next_ = this;
prev->next_ = node;
prev_ = node;
}
void erase() noexcept {
auto next = next_;
auto prev = prev_;
prev->next_ = next;
next->prev_ = prev;
}
size_t size() const noexcept {
size_t count = 0;
for(auto node = next_; node != this; node = node->next_)
++count;
return count;
}
};
template<class T>
class Tracker : private AutoListNode
{
protected:
static AutoListNode objects_;
Tracker() noexcept { objects_.push_back(this); }
Tracker(Tracker const&) noexcept { objects_.push_back(this); }
public:
static auto count() noexcept { return objects_.size(); }
};
template<class T>
AutoListNode Tracker<T>::objects_;
- std::unordered_map 类型对象声明期间出现"field has incomplete type"错误
- C++ 多态模板类,模板类型对象的实例化
- 如何分配适合容纳 T 类型对象的缓冲区(可能过度对齐、可能有运算符 new 等)
- 如何构造一个 std::variant 类型对象,其自身 Templated 和构造函数转发参数
- C++:初始化指向具有不同类型对象的指针数组
- 在类 C++ 中构造的模板类型对象
- 如何将颁发者名称设置为x509_req类型对象
- 将任何数据类型/对象作为参数传递以确定其大小
- 将引用类型对象的数组从C#封送到C++
- <T> 从类型对象创建类型<T1>对象的构造函数
- C++是否有现有的方法来检查对象是否是派生类型对象
- C 模板:创建与现有对象相同的类型对象
- 链接列表中的虚函数 - 多种返回类型(对象)
- 没有适当操作员()的类型对象的呼叫
- 制作垫子类型对象的数组.输出窗口显示同一帧
- 抽象类型对象的分配
- 在std::list中就地创建自定义类型对象
- 接受泛型列表类型对象的参数
- C++-将模板类型对象强制转换为特定的数据类型
- 试图在C++中打印存储在类型对象数组中的信息