我正在尝试为我的子类实现一个简单的继承单例模式。 因此,我正在实现一个父类,并且因为我想让其他人尽可能容易地创建一个新的 Singleton 子类,所以我需要在父类构造函数内部处理子类的 Singleton 实现所需的所有操作类。
#include <vector>
#include <typeinfo>
#include <iostream>
class Father
{
protected:
Father()
{
for(auto & instance : Father::singletonInstances)
if(typeid(instance) == typeid(this)) // typeid(this) will always be "Father", which is actually the issue
{
// Singleton instance already exists for this class
* this = instance;
std::cout<<"An instance of the given class is already active\n";
return;
}
std::cout<<"Constructed\n";
// Otherwise, mark this as the Singleton instance for this class
Father::singletonInstances.emplace_back(this);
}
public:
Father operator=(Father * inputObj) { return * inputObj; }
private:
static std::vector<Father *> singletonInstances;
};
std::vector<Father *> Father::singletonInstances;
class Child : protected Father
{
public:
Child() : Father() {}
};
class Child2 : protected Father
{
public:
Child2() : Father() {}
};
int main()
{
new Child();
new Child2();
return 0;
}
输出:
Constructed
An instance of the given class is already active
所以,再次澄清一下: - 问题是 typeid(this) 在构造函数中总是“父亲” - 新的 child ();新的 Child2();应该允许 - 新的 child ();新的 child ();不应该被允许 - 不应对子类进行任何修改
我知道我对 Singleton 的实现可能看起来很奇怪。我乐于接受新想法。
我能够在 JScript 中实现这些想法,但在 C++ 中我似乎无法找到使其工作的方法。
最佳答案
当创建具有继承的类时,首先调用基类构造函数,然后在层次结构中向上调用子类。这意味着在Father
的构造函数中,Child/Child2
还没有构造。
在构造对象之前尝试使用该对象可能会导致未定义的行为。 C++ 试图保护你免受这种情况的影响。阅读例如 the FAQ Lite .这不是完全相同的东西,但是相关联并阅读本文应该让您了解为什么 typeid
会说该对象是 Father
。
关于 cppreference我们可以阅读
If typeid is used on an object under construction or destruction (in a destructor or in a constructor, including constructor's initializer list or default member initializers), then the std::type_info object referred to by this typeid represents the class that is being constructed or destroyed even if it is not the most-derived class.
我见过几种实现单例的方法,最现代的似乎是返回对静态函数对象的引用。这是一个想法。
#include <iostream>
template <typename T>
T& Singleton() {
static T single;
return single;
}
class Foo {
private:
Foo() {
std::cout << "Constructed" << std::endl;
}
friend Foo& Singleton<Foo>();
public:
void print() {
std::cout << "Foo" << std::endl;
}
};
int main() {
//Foo f; not allowed
Singleton<Foo>().print();
Singleton<Foo>().print();
}
这要求每个单例实例都有一个私有(private)构造函数并友好
模板实例化。只允许 Singleton
函数构造一个 Foo
并且它只会构造 1 个拷贝。它也是线程安全的,您无需担心清理问题。如果您四处搜索,可以找到其他方法。
关于C++单例继承问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50786149/