提问



作为一名C#开发人员,我曾经经历过构造函数:[26]




class Test {
    public Test() {
        DoSomething();
    }

    public Test(int count) : this() {
        DoSomethingWithCount(count);
    }

    public Test(int count, string name) : this(count) {
        DoSomethingWithName(name);
    }
}


有没有办法在C ++中执行此操作?


我尝试调用类名并使用this关键字,但都失败了。

最佳参考


C ++ 11:是的!


C ++ 11及其后续版本具有相同的功能(称为委托构造函数)。 [27]


语法与C#略有不同:


class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {}
};


C ++ 03:否


不幸的是,在C ++ 03中没有办法做到这一点,但有两种模拟方法:



  1. 您可以通过默认参数组合两个(或更多)构造函数:


    class Foo {
    public:
      Foo(char x, int y=0);  // combines two constructors (char) and (char, int)
      // ...
    };
    

  2. 使用init方法共享公共代码:


    class Foo {
    public:
      Foo(char x);
      Foo(char x, int y);
      // ...
    private:
      void init(char x, int y);
    };
    
    Foo::Foo(char x)
    {
      init(x, int(x) + 7);
      // ...
    }
    
    Foo::Foo(char x, int y)
    {
      init(x, y);
      // ...
    }
    
    void Foo::init(char x, int y)
    {
      // ...
    }
    



请参阅C ++ FAQ条目以供参考。[28]

其它参考1


不,你不能在C ++ 03中调用另一个构造函数(称为委托构造函数)。


这在C ++ 11(又名C ++ 0x)中发生了变化,它增加了对以下语法的支持:

(来自维基百科的例子)[29]


class SomeType
{
  int number;

public:
  SomeType(int newNumber) : number(newNumber) {}
  SomeType() : SomeType(42) {}
};

其它参考2


我相信你可以从构造函数中调用构造函数。它将编译并运行。我最近看到有人这样做,它在Windows和Linux上运行。


它只是没有做你想要的。内部构造函数将构造一个临时的本地对象,一旦外部构造函数返回就会被删除。它们也必须是不同的构造函数,否则你将创建一个递归调用。


参考:https://isocpp.org/wiki/faq/ctors#init-methods [30]

其它参考3


值得指出的是,可以在构造函数中调用父类的构造函数,例如:


class A { /* ... */ };

class B : public A
{
    B() : A()
    {
        // ...
    }
};


但是,不,你不能调用同一个类的另一个构造函数。

其它参考4


在C ++ 11中,构造函数可以调用另一个构造函数重载:[31] [32]


class Foo  {
     int d;         
public:
    Foo  (int i) : d(i) {}
    Foo  () : Foo(42) {} //New to C++11
};


此外,成员也可以像这样初始化。


class Foo  {
     int d = 5;         
public:
    Foo  (int i) : d(i) {}
};


这应该消除了创建初始化辅助方法的需要。并且仍然建议不要在构造函数或析构函数中调用任何虚函数,以避免使用任何可能未初始化的成员。

其它参考5


如果你想成为邪恶的,你可以使用就地新运算符:


class Foo() {
    Foo() { /* default constructor deliciousness */ }
    Foo(Bar myParam) {
      new (this) Foo();
      /* bar your param all night long */
    } 
};


似乎适合我。


修改


正如@ElvedinHamzagic指出的那样,如果Foo包含一个分配内存的对象,那么该对象可能不会被释放。这使事情进一步复杂化。


一个更一般的例子:


class Foo() {
private:
  std::vector<int> Stuff;
public:
    Foo()
      : Stuff(42)
    {
      /* default constructor deliciousness */
    }

    Foo(Bar myParam)
    {
      this->~Foo();
      new (this) Foo();
      /* bar your param all night long */
    } 
};


看起来有点不那么优雅,当然。 @JohnIdol的解决方案要好得多。

其它参考6


不,在C ++中,您无法从构造函数中调用构造函数。沃伦指出,你可以做的是:



  • 使用不同的签名重载构造函数

  • 在参数上使用默认值,以使更简单的版本可用



请注意,在第一种情况下,您无法通过从另一个构造函数调用来减少代码重复。您当然可以使用单独的private/protected方法来执行所有初始化,并让构造函数主要处理参数处理。

其它参考7


在Visual C ++中,您还可以在构造函数中使用此表示法:this-> Classname :: Classname(另一个构造函数的参数)。请参阅以下示例:


class Vertex
{
 private:
  int x, y;
 public:
  Vertex(int xCoo, int yCoo): x(xCoo), y(yCoo) {}
  Vertex()
  {
   this->Vertex::Vertex(-1, -1);
  }
};


我不知道它是否在其他地方工作,我只在Visual C ++ 2003和2008中测试过它。你也可以用这种方式调用几个构造函数,我想,就像在Java和C#中一样。


P.S。:坦率地说,我很惊讶这是前面没有提到的。

其它参考8


如果我正确理解你的问题,你会问你是否可以在C ++中调用多个构造函数?


如果这就是你要找的东西,那么不 - 那是不可能的。


您当然可以拥有多个构造函数,每个构造函数都具有唯一的参数签名,然后在实例化新对象时调用所需的构造函数。


你甚至可以在最后有一个带有默认参数的构造函数。


但是你可能没有多个构造函数,然后分别调用它们。

其它参考9


另一个尚未显示的选项是将您的类拆分为两个,在原始类周围包装一个轻量级接口类,以实现您正在寻找的效果:


class Test_Base {
    public Test_Base() {
        DoSomething();
    }
};

class Test : public Test_Base {
    public Test() : Test_Base() {
    }

    public Test(int count) : Test_Base() {
        DoSomethingWithCount(count);
    }
};


如果你有许多构造函数必须调用它们的下一级对应物,这可能会变得混乱,但对于少数构造函数,它应该是可行的。

其它参考10


我建议使用private friend方法来实现构造函数的应用程序逻辑,并由各种构造函数调用。这是一个例子:


假设我们有一个名为StreamArrayReader的类,其中包含一些私有字段:


private:
    istream * in;
      // More private fields


我们想要定义两个构造函数:


public:
    StreamArrayReader(istream * in_stream);
    StreamArrayReader(char * filepath);
    // More constructors...


第二个只使用第一个(当然我们不想复制前者的实现)。理想情况下,人们想做的事情如下:


StreamArrayReader::StreamArrayReader(istream * in_stream){
    // Implementation
}

StreamArrayReader::StreamArrayReader(char * filepath) {
    ifstream instream;
    instream.open(filepath);
    StreamArrayReader(&instream);
    instream.close();
}


但是,在C ++中不允许这样做。出于这个原因,我们可以定义一个私有方法如下,它实现了第一个构造函数应该做的事情:


private:
  friend void init_stream_array_reader(StreamArrayReader *o, istream * is);


现在这个方法(因为它是朋友)可以访问o的私有字段。然后,第一个构造函数变为:


StreamArrayReader::StreamArrayReader(istream * is) {
    init_stream_array_reader(this, is);
}


请注意,这不会为新创建的副本创建多个副本。第二个成为:


StreamArrayReader::StreamArrayReader(char * filepath) {
    ifstream instream;
    instream.open(filepath);
    init_stream_array_reader(this, &instream);
    instream.close();
}


也就是说,而不是让一个构造函数调用另一个构造函数,它们都会调用私人朋友!

其它参考11


这种方法可能适用于某些类(当赋值运算符表现很好时):


Foo::Foo()
{
    // do what every Foo is needing
    ...
}

Foo::Foo(char x)
{
    *this = Foo();

    // do the special things for a Foo with char
    ...
}

其它参考12


在调用构造函数时,它实际上是从堆栈或堆中分配内存。因此,在另一个构造函数中调用构造函数会创建一个本地副本。所以我们正在修改另一个对象,而不是我们关注的对象。

其它参考13


简单地说,你不能在C ++ 11之前。


C ++ 11引入了委托构造函数:[33]



  

委派构造函数


  
  如果类的名称本身在类中显示为class-or-identifier
  成员初始化列表,然后列表必须包含该成员
  仅初始化程序;这样的构造函数称为委托
  构造函数,以及由唯一成员选择的构造函数
  初始化列表是目标构造函数

  
  在这种情况下,目标构造函数由重载选择
  解析并先执行,然后控件返回到
  委托构造函数及其正文被执行。

  
  委托构造函数不能递归。


class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char,int)
};



请注意,委托构造函数是一个全有或全无的提议;如果构造函数委托给另一个构造函数,则调用构造函数不允许在其初始化列表中包含任何其他成员。如果您考虑初始化const/reference成员一次,那么这是有道理的。

其它参考14


会更容易测试,而不是决定:)
尝试这个:


#include <iostream>

class A {
public:
    A( int a) : m_a(a) {
        std::cout << "A::Ctor" << std::endl;    
    }
    ~A() {
        std::cout << "A::dtor" << std::endl;    
    }
public:
    int m_a;
};

class B : public A {
public:
    B( int a, int b) : m_b(b), A(a) {}
public:
    int m_b;
};

int main() {
    B b(9, 6);
    std::cout << "Test constructor delegation a = " << b.m_a << "; b = " << b.m_b << std::endl;    
    return 0;
}


并用98 std编译它:
    g ++ main.cpp -std=c ++ 98 -o test_1


你会看见:


A::Ctor
Test constructor delegation a = 9; b = 6
A::dtor


所以:)