【问题标题】:Template class: No appropriate default constructor avaialable. But some of my classes cannot have default constructors模板类:没有合适的默认构造函数可用。但是我的一些类不能有默认构造函数
【发布时间】:2011-11-09 06:16:50
【问题描述】:

我遇到了一个奇怪的问题,我需要有一个默认构造函数才能让我的模板类工作,但我想与模板一起使用的一些类不能有默认构造函数。

我的意思是某些类不能有默认构造函数是它们有一个 const 引用字段,因此,它们必须在构造函数/初始化列表中设置。如果我有默认构造函数,则无需设置这些引用。

所以,我想有两种可能的解决方案:有时在模板类中找到允许非默认构造函数的方法,或者找到在默认构造函数中设置 const 引用字段的方法。

我该如何解决这个问题?

这是我的模板代码:

#pragma once

template<class T>
class Singleton
{
public:
    static T* getInstance()
    {
        if(!instance) instance = new T;
        return instance;
    }
static void setInstance(T* inst)
{
    instance = inst;
}
protected:
    Singleton();
    ~Singleton();
private:
    Singleton(Singleton const&);
    Singleton& operator=(Singleton const&);
    static T* instance;
};

template<class T> T* Singleton<T>::instance = 0;

这是我设置 const 引用的地方(在 .cpp 中):

InputHandler::InputHandler(const sf::Input& inputObject)
    : input(inputObject)
{

并且输入在header中定义:

const sf::Input& input;

由于这个代码区域(在不同的文件中),我必须使用常量引用:

const sf::Input& input = window.GetInput();
InputHandler* inputHandler = new InputHandler(input);
Singleton<InputHandler>::setInstance(inputHandler);

GetInput() 不是我的方法之一,它必须返回一个 const sf::Input&

【问题讨论】:

  • 你为什么使用参考会员?
  • 看代码无法回答你的问题。添加模板类的相关部分。
  • 为什么模板需要它的参数来拥有默认构造函数?在不知道是否应该修改模板而不需要它或修改类以拥有它的情况下,这是不可能的。
  • 我在问题中添加了我的代码,所以我希望现在更清楚发生了什么。
  • 我会认真考虑重新设计。以下是关于 Singleton 反模式的一些 thoughts

标签: c++


【解决方案1】:

您正在调用 getInstance 中的默认构造函数:

instance = new T;

如果有人在 setInstance 之前调用 getInstance 会发生什么?

如果在 setInstance 之前调用 getInstance 是错误的,那么如果在设置实例之前调用 getInstance,则应该断言或抛出或返回 NULL。只要去掉new T,你的代码就可以编译了。

如果在 setInstance 之前调用 getInstance 不是错误,那么你就没有真正的单例。早期的调用者会收到一个默认构造的对象,后来的调用者会得到一个集合。这是两个实例,因此不是单例。

【讨论】:

  • 我认为对于某些对象,只需调用 getInstance 而无需调用 setInstance 会很方便,因为这样我就不必担心从项目的各个区域调用 getInstance 时实例为空.我永远不会遇到你两者都做的情况,但我猜编译器不会知道这一点。如果我不能让它工作,我只需要更加小心地以正确的顺序设置/获取实例。
【解决方案2】:

如果你有一个引用成员,那么你不能(明智地)使你的类默认可构造或可分配,因为引用必须被初始化,并且不能被重新分配。

如果您需要类中的这些属性,那么您可能希望该成员是一个指针,默认情况下初始化为 null 并在需要时稍后分配。

【讨论】:

  • 我意识到你在我提供代码之前写了这个答案,但现在我希望很清楚我不能为此使用指针(我希望我可以)
  • 完全不清楚不能使用指针。您是说您认为InputHandler::input 必须是引用,而不是指针,因为它是从引用初始化的?只需将其设为指针,并使用input(&amp;inputObject) 对其进行初始化。
  • @Petwoip:虽然你最好认真重新考虑一下你对 Singleton 反模式的奇怪扭曲。如果您只是创建一个InputHandler 并将引用传递给需要它的任何其他类,那么您根本不需要默认构造函数。作为奖励,您还将修复内存泄漏、线程安全问题以及因使用全局变量而导致的过度耦合的维护问题。
【解决方案3】:

您也许可以让 Singleton 构造函数设置实例指针,即

Singleton::Singleton()
{
    assert(instance == nullptr);
    instance = static_cast<T*>(this);
}

然后您可以从接口中删除 setInstance 函数,getInstance 可以简单地返回实例。

作为对评论的回应,我假设类是这样定义的:

class MyClassThatShouldBeASingleton : public Singleton<MyClassThatShouldBeASingleton>
{
};

当然,这确实意味着您需要显式设置这样的单例,而不是像在原始代码中那样自动实例化。这不一定是您希望所有单例的工作方式,只是解决问题的一种方法。

【讨论】:

  • 我不在家里有这个项目的电脑,所以我现在不能测试这个。我很好奇这是如何工作的,因为它似乎根本没有调用 T 构造函数。也许我对模板或 static_cast 有误解。
  • 这不会编译(如果编译了那就是无稽之谈),因为this 是一个指向Singleton&lt;T&gt; 的指针,它是与T 无关的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多