1054

作为一名C#开发人员,我习惯于通过构造函数运行:

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

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

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

有没有办法在 C++ 中做到这一点?

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

4

15 回答 15

1402

C++11:是的!

C++11 及更高版本具有相同的功能(称为委托构造函数)。

语法与 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 条目以供参考。

于 2008-11-21T10:04:17.963 回答
129

是和否,取决于 C++ 的版本。

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

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

class SomeType
{
  int number;
 
public:
  SomeType(int newNumber) : number(newNumber) {}
  SomeType() : SomeType(42) {}
};
于 2008-11-21T10:00:12.417 回答
49

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

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

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

于 2009-08-12T15:31:52.917 回答
37

C++11:是的!

C++11 及更高版本具有相同的功能(称为委托构造函数)。

语法与 C# 略有不同:

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

C++03:没有

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

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

但是,不,您不能在 C++03 之前调用同一类的另一个构造函数。

于 2008-11-22T06:36:13.657 回答
23

C++11中,构造函数可以调用另一个构造函数重载

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) {}
};

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

于 2011-09-22T20:07:00.453 回答
17

如果你想作恶,你可以使用就地的“new”操作符:

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 的解决方案要好得多。

于 2011-03-24T16:53:45.940 回答
12

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

C++11 引入了委托构造函数

委托构造函数

如果类本身的名称在成员初始化器列表中显示为类或标识符,则列表必须仅包含一个成员初始化器;这样的构造函数称为委托构造函数,由初始化列表的唯一成员选择的构造函数是目标构造函数

在这种情况下,通过重载决议选择目标构造函数并首先执行,然后控制返回到委托构造函数并执行其主体。

委托构造函数不能是递归的。

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

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

于 2017-10-28T11:53:30.413 回答
11

不,在 C++ 中,您不能从构造函数调用构造函数。正如沃伦指出的那样,您可以做的是:

  • 使用不同的签名重载构造函数
  • 在参数上使用默认值,以提供“更简单”的版本

请注意,在第一种情况下,您不能通过从另一个构造函数调用一个构造函数来减少代码重复。您当然可以有一个单独的、私有/受保护的方法来完成所有初始化,并让构造函数主要处理参数处理。

于 2008-11-21T09:56:18.400 回答
7

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

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

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

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

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

于 2011-11-25T00:54:11.947 回答
5

在 Visual C++ 中,您还可以在构造函数中使用此表示法:this->Classname::Classname(parameters of another constructor)。请参见下面的示例:

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# 中一样。

PS:坦率地说,我很惊讶之前没有提到这一点。

于 2012-02-20T10:00:51.643 回答
2

我建议使用一种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();
}

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

于 2014-11-02T00:19:49.997 回答
2

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

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

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

    // do the special things for a Foo with char
    ...
}
于 2015-11-10T21:18:53.230 回答
0

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

如果那是您正在寻找的东西,那么不-那是不可能的。

你当然可以有多个构造函数,每个都有唯一的参数签名,然后在你实例化一个新对象时调用你想要的那个。

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

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

于 2008-11-21T09:49:40.923 回答
0

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

于 2014-01-06T10:52:33.987 回答
-1

比决定更容易测试:)试试这个:

#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

所以 :)

于 2016-09-09T10:38:09.417 回答