简体   繁体   English

命名构造函数和临时生命周期扩展

[英]Named constructors and temporary lifetime extension

I'm looking for a way to define a "base" constructor, that will initialize values using defaults, and then extend that base into a number of specialized constructors. 我正在寻找一种方法来定义一个“基础”构造函数,它将使用默认值初始化值,然后将该基础扩展为许多专门的构造函数。

The pseudocode of what I want might look like: 我想要的伪代码可能是这样的:

class Foo{
private:
    int val;
    /* ... */

public:
    // Base constructor
    Foo(){ /*...*/ }           // This provides basic initialization of members

    // Named constructors
    static Foo fromString(string s){
        Foo f;                 // Call base constructor
        f.val = s.length();    // Customize base object
        return f;              // Return customized object
    }
    static Foo fromInt(int v){
        Foo f;
        f.val = v;
        return f;
    }
}

At first, I thought about extending the lifetime of the temporary f , but the const declaration prevents me from editing its members. 起初,我考虑过延长临时f的生命周期 ,但const声明阻止我编辑其成员。 So it seems this is out. 所以看来这已经结束了。

Then I tried the "named constructor" approach (which is shown above). 然后我尝试了“命名构造函数”方法(如上所示)。 However, I had to modify the example to create the object first, then modify it, then return it. 但是,我必须先修改示例以创建对象,然后修改它,然后返回它。 This seems to work, but I'm reasonably confident that it is just a coincidence since f is a temporary and goes out of scope at the end of the function. 这似乎有效,但我有理由相信这只是一个巧合,因为f是一个临时的,并且在函数结束时超出了范围。

I've also considered using something like auto_ptr s, but then I'm working with both Foo objects as well as auto_ptr s to Foo, and this makes the rest of the code "care" whether objects are created via the base constructor (in which case it would be an object) or via one of the extended constructors (in which case it would be a pointer). 我也考虑过使用类似auto_ptr的东西,但后来我正在使用Foo对象和auto_ptr到Foo,这使得其余的代码“关心”对象是否通过基础构造函数创建(在在哪种情况下它将是一个对象)或通过一个扩展构造函数(在这种情况下它将是一个指针)。

If it helps, in Python, I would use something like this: 如果它有用,在Python中,我会使用这样的东西:

class Foo(object):
    def __init__(self):
        /* Basic initialization */

    @classmethod
    def fromString(cls, s):
        f = Foo() #†
        f.val = len(s)
        return f

Lastly, there are two reasons I want to do it this way: 最后,有两个原因我想这样做:

  1. Code reuse, I would like to move the common initialization out of each of the constructors and into one. 代码重用,我想将每个构造函数的公共初始化移动到一个。 I realize I can do this via an init() -type private method called by each constructor, but I just wanted to mention this. 我意识到我可以通过每个构造函数调用的init()类型私有方法来做到这一点,但我只想提一下。
  2. Clarity and resolve ambiguity. 清晰并解决歧义。 Much like the motivation for the named constructor example, parameter types by themselves aren't enough to determine which ctor should be used. 与命名构造函数示例的动机非常相似,参数类型本身不足以确定应该使用哪个ctor。 Additionally, the fromSomething syntax provides excellent clarity. 此外, fromSomething语法提供了极好的清晰度。

Forgive me if there is a simple solution, my work has shifted from c++ to Java/Python for the past few years so I'm a bit rusty. 请原谅我,如果有一个简单的解决方案,过去几年我的工作已从c ++转移到Java / Python,所以我有点生疏了。

This is perfectly valid: 这完全有效:

static Foo fromInt(int v){
    Foo f;
    f.val = v;
    return f;
}

This invokes Foo 's copy constructor when you return f (probably the compiler applies return value optimization , so no copies are made). 这会在您返回f时调用Foo的复制构造f (可能编译器应用返回值优化 ,因此不会生成副本)。 f goes out of scope, but the return value is just a copy of it, so this is totally valid, it's not just "a coincidence" that it's working. f超出范围,但返回值只是它的副本,所以这是完全有效的,它不仅仅是“巧合”,它正在发挥作用。

So if your worries about using the named constructor approach is just that you don't really know if it works, go ahead with it, it works perfectly. 因此,如果你担心使用命名的构造函数方法只是你不知道它是否有效,那么继续它,它完美地工作。

In C++11, you can call other constructors from constructors: 在C ++ 11中,您可以从构造函数中调用其他构造函数:

struct X{
  X() : ... { ... }
  X(int i) : X() { ... }
  X(std::string s) : X() { ... }
};

For C++03, the named constructor approach is likely the best and perfectly reasonable, IMHO. 对于C ++ 03,命名的构造函数方法可能是最好的,也是完全合理的,恕我直言。

Why not: 为什么不:

class Foo{
private:
    int val;
    void Init(int v = <some default value>/*What ever here *));
    /* ... */


public:
    // Base constructor
    Foo(){ Init(); }           // This provides basic initialization of 
    Foo(string &s) { Init(s.length); };
    Foo(int v) { Init(v); };
};

Seems simpler. 似乎更简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM