【问题标题】:C++ privately constructed classC++ 私有构造类
【发布时间】:2010-11-25 10:36:05
【问题描述】:

如何调用函数并使构造函数保持私有?如果我将类设为静态,我需要声明编译器用来调用构造函数的对象名称,如果构造函数是私有的(对象也是无关的),则不能。这是我尝试使用的代码(它不可编译):

我想让构造函数保持私有,因为稍后我将在添加对象之前进行大量检查,当所有提交的变量都不唯一时修改以前的对象,而不是创建新对象。

#include <iostream>
#include <fstream>
#include <regex>
#include <string>
#include <list>
#include <map>

using namespace std;
using namespace tr1;

class Referral
{
public:
    string url;
    map<string, int> keywords;

    static bool submit(string url, string keyword, int occurrences)
    {
        //if(Referrals.all.size == 0){
        //  Referral(url, keyword, occurrences);
        //}
    }

private:
    list<string> urls;

    Referral(string url, string keyword, int occurrences)
    {
        url = url;
        keywords[keyword] = occurrences;
        Referrals.all.push_back(this);
    }
};

struct All
{
    list<Referral> all;
}Referrals;

int main()
{
    Referral.submit("url", "keyword", 1);
}

【问题讨论】:

  • 你能更清楚你的目标是什么吗?看起来您正在尝试保留所有推荐实例的列表。为什么要让构造函数保持私有?

标签: c++ class static constructor private


【解决方案1】:

私有构造函数和静态工厂方法有什么问题?

class Example {
  Example() { ... }
public:
  static Example CreateExample() {
    return Example();
  }
};

【讨论】:

    【解决方案2】:

    根据您的main 代码,我认为您要拍摄的是一个单例,它看起来像:

    class Referral
    {
    private:
        Referral()
        {
            //...
        }
    
    public:
        static Referral& instance()
        {
            static Referral instance_s;
            return instance_s;
        }
    
        bool submit(string url, string keyword, int occurrences)
        {
            //...
        }
    };
    

    那么您在main 中的调用将如下所示:

    int main()
    {
        Referral::instance().submit("url", "keyword", 1);
    }
    

    另一种可能性是您希望保留一份推荐人列表,在这种情况下,您可以使用 struct 和他们的列表来完成您正在寻找的内容:

    struct Referral
    {
        Referral(string url, string keyword, int occurrences) :
            url_m(url), keyword_m(keyword), occurrences_m(occurrences)
        { }
    
        string url_m;
        string keyword_m;
        int    occurrences_m;
    };
    
    typedef std::vector<Referral> ReferralSet;
    

    那么您在main 中的调用将如下所示:

    int main()
    {
        ReferralSet set;
    
        set.push_back(Referral("url", "keyword", 1));
    }
    

    【讨论】:

    • 我不是为单身而拍摄,尽管我明白你的想法。这只是我稍后将实施的多个检查案例的一个非常非常简化的版本。不过谢谢,我仍然会看看我是否可以使用这种类型的实现,不管是这个还是其他。
    • 这个想法还是一样的——将instance()重命名为createInstance(),并实现它每次都返回一个新的对象实例。构造函数仍然是私有的。
    • 使用 instance().submit 比 Chickencha 省略它的实现有什么好处?
    • 我使用的 instance() 例程保留了引用实例——Chickencha 的版本在内部创建了一个临时引用,正如他在回答中指出的那样。
    • 我认为所描述的 createInstance() 基本上是您现在正在尝试使用 Submit() 函数执行的操作。 createInstance() 更好地描述了函数的使用 IMO,但这是您的代码。
    【解决方案3】:

    首先,您需要将 Submit 设为静态函数。那你可以说

    Referral::Submit( url, keyword, occurrences );
    

    不创建引用实例。

    然后,在您的 Submit 函数中,您只是创建了一个临时的 Referral 对象,该对象几乎立即消失。可能您想要做的是使用 new 动态创建一个实例。根据您希望如何管理它,您可能希望将推送到列表中的代码移动到提交中。

    最后,我会将您的引用实例列表设为静态成员变量,而不是您现在的方式。

    (另外,通过引用传递这些字符串参数可能是个好主意。)

    【讨论】:

    • 你能解释一下通过引用传递的好处吗?
    • 按值传递(这是您现在正在做的)创建对象的副本。因此,每次调用其中一个函数时,都会不必要地调用字符串的复制构造函数。由于您没有修改传入的字符串,因此您可以通过引用将其传入并使其成为常量并避免那些复制构造函数调用。通过引用传递非原始类型(int、float、char 等)的任何内容并在可能的情况下将其设为 const 通常是一种好习惯。
    • @Chickecha:当 Referral 对象将自己添加到列表中时,它正在创建一个副本,因此虽然该方法仅创建一个临时对象,但列表中有一个包含临时内容的新对象。
    • 是的,如果代码是 Referrals.all.push_back(*this);但是代码没有取消引用 this 指针。很难判断编码器是打算存储指针还是对象。 (我认为存储指针更好。)
    【解决方案4】:

    虽然整个代码有一些气味,但您只需进行与您的问题无关的微小更改即可使其正常工作。

    为了使其编译,我删除了正则表达式包含(我没有使用支持 C++0x 的编译器)和“使用命名空间 tr1”。将构造函数实现移到引用全局对象的定义之后。更改 .当您引用静态方法时,在 main 函数中使用 ::。

    // changes...
    //#include <regex>
    ...
    //using namespace tr1;
    ...
    class Referral { 
    ...
        Referral(string url, string keyword, int occurrences); // added ; moved the implementation bellow the Referrals variable definition
    ...
    struct All  {
    ...
    } Referrals;
    
    // added constructor implementation here (Referrals global must be defined before use):
    Referral::Referral(string url, string keyword, int occurrences)
    {
       url = url;
       keywords[keyword] = occurrences;
       Referrals.all.push_back(*this); // added dereference, this is of type Referral*, not Referral
    }
    
    int main()
    {
       Referral::submit("url","keyword",1);
    }
    

    现在,从设计的角度来看,代码有一股恶臭。如果真的想要一个全局列表来添加您的 Referral 对象,请考虑将其设置为 Referral 类的私有静态属性,以便您可以对其进行更多控制(只有 Referral 类中的方法可能会破坏内容)。将所有属性设为私有,并仅提供用户代码所需功能的访问器(在大多数情况下,只读访问就足够了)。在您的构造函数中使用初始化列表,并按照它们在类定义中出现的相同顺序初始化那里的所有成员。

    所有这些都解决了,它仍然有一些气味。静态函数创建类的一个实例,但构造函数是包含在地图中的实例(??)如果构造函数不与地图交互,并且 submit() 方法将创建对象,然后将其包含在列表中...

    我认为你可能会从表达你打算做的事情中受益,这里的许多人会帮助你选择设计和理由。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      • 2016-09-11
      相关资源
      最近更新 更多