一千萬個為什麽

搜索

具有繼承的Singleton,Derived類無法在父實例中實例化?

下面的代碼基於環境變量實例化派生的單例對象。編譯器錯誤說錯誤C2512:'Dotted':沒有合適的默認構造函數。我不明白編譯器在抱怨什麽。

編輯: 修復了實現get實例方法的問題,該方法需要定義父類和派生類。通過在單獨的頭文件中分離類定義,並在實現實例函數的Singleton.cpp中包含相同的類定義。

Mainfile – 1
#include 
#include 
#include "Singleton.h"
using namespace std;

int main(){

     Singleton::instant().print();
     cin.get();
}
Singleton.h
#pragma once
#include 
using std::cout;
class Singleton{
public:
    static Singleton & instant();
    virtual void print(){cout<<"Singleton";}
protected:
    Singleton(){};
private:
    static Singleton * instance_;
    Singleton(const Singleton & );
    void operator=(const Singleton & );

};

Singleton.cpp
#include "Singleton.h"
#include "Dotted.h"
Singleton * Singleton::instance_ = 0;
Singleton & Singleton::instant(){
    if (!instance_)
    {
        char * style = getenv("STYLE");
        if (style){
            if (strcmp(style,"dotted")==0)
            {
                instance_ = new Dotted();
                return *instance_; 
            }           else{
                instance_ = new Singleton();
                return *instance_;
            }       
        }

        else{
            instance_ = new Singleton();
            return *instance_;
        }
    }
    return *instance_;

}
Dotted.h

#pragma once
class Dotted;

class Dotted:public Singleton{
public:
    friend class Singleton;
    void print(){cout<<"Dotted";}
    private:
        Dotted(){};

};

最佳答案

您的代碼有幾個問題:

  • You mean to return type Singleton& or const Singleton&. You are currently returning by value, which is attempting to invoke a copy constructor, and no such constructor exists.
  • Your default constructor in Dotted probably is not available in Singleton. I suggest you make Singleton a friend of Dotted so that it is able to access that constructor. Although not 100% sure on this one.
  • You forgot to make the function print() virtual, so your override won't manifest itself.
  • You have put "friend" in the wrong place; you need to declare Singleton a friend of Dotted in Dotted, not within Singleton.
  • You should not make your definition of Singleton::instant inline as it needs to construct an instance of Dotted and, in order to do that, it needs to see Dotted's definition. So you should move that to a source file where it is able to see both Dotted and Singleton's complete definitions, respectively.
  • You need to put Singleton* Singleton::instance_ = 0; in a source file somewhere.
  • You are missing an else clause in your if(!style) section; currently, if the STYLE environment variable is set, but isn't set to "dotted", then you end up returning a null singleton.

除上述內容外,我強烈建議您避免環境變量和單身人士。它們都是“共享可變狀態”的例子,並且可能導致很多混亂。單身人士雖然已經出現在“設計模式”書籍中已有相當長的一段時間,但現在被理解為設計反模式。這是一種更靈活的方法,可以讓你傳遞一個接口並簡單地實例化一次,而不是將它存在於其API中。

例如,對於您的特定情況,我建議如下:

class Printer
{
    public:
        virtual ~Printer(){}
        virtual void print()const = 0
};

class StringPrinter : public Printer
{
    public:
         StringPrinter() : _str("") {}
         StringPrinter(const std::string& str) : _str(str) {}
         StringPrinter(const StringPrinter& o) : _str(o._str) {}
         virtual ~StringPrinter(){}
         virtual void print()const{ std::cout << _str << std::endl; }
         StringPrinter& operator=(const StringPrinter& o){ _str = o._str; return *this;}
    private:
         std::string _str;         
};

Then, in any class where you previously used Singleton, simply take a const Printer& object. And print to that object. Elsewhere, you can conditionally construct a StringPrinter("Singleton") or StringPrinter("dotted"). Or possibly some other instance of that interface, although I would suggest using QSettings or some sort of configuration file in place of environment variables, or at least use MYAPPLICATIONNAME_STYLE instead of just STYLE; in other words, if you are going to go the environment variable route, at least qualify its name.

轉載註明原文: 具有繼承的Singleton,Derived類無法在父實例中實例化?