作为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'关键字,但都失败了。
答案 0 :(得分:1124)
C ++ 11:是的!
C ++ 11及更高版本具有相同的功能(称为delegating constructors)。
语法与C#略有不同:
class Foo {
public:
Foo(char x, int y) {}
Foo(int y) : Foo('a', y) {}
};
C ++ 03:否
不幸的是,在C ++ 03中无法做到这一点,但有两种模拟方法:
您可以通过默认参数组合两个(或更多)构造函数:
class Foo {
public:
Foo(char x, int y=0); // combines two constructors (char) and (char, int)
// ...
};
使用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)
{
// ...
}
请参阅the C++FAQ entry以供参考。
答案 1 :(得分:107)
不,你不能在C ++ 03中调用另一个构造函数(称为委托构造函数)。
这在C ++ 11(又名C ++ 0x)中有所改变,它增加了对以下语法的支持:
(例子来自Wikipedia)
class SomeType
{
int number;
public:
SomeType(int newNumber) : number(newNumber) {}
SomeType() : SomeType(42) {}
};
答案 2 :(得分:40)
我相信你可以从构造函数中调用构造函数。它将编译并运行。我最近看到有人这样做,它在Windows和Linux上运行。
它只是没有做你想要的。内部构造函数将构造一个临时本地对象,一旦外部构造函数返回,该对象就会被删除。它们也必须是不同的构造函数,否则你将创建一个递归调用。
答案 3 :(得分:22)
值得指出的是,可以在构造函数中调用父类的构造函数,例如:
class A { /* ... */ };
class B : public A
{
B() : A()
{
// ...
}
};
但是,不,你不能调用同一个类的另一个构造函数。
答案 4 :(得分:18)
在C++11,constructor can call another constructor overload:
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 :(得分:12)
如果你想变得邪恶,你可以使用就地“新”算子:
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 :(得分:8)
不,在C ++中,您无法从构造函数中调用构造函数。正如沃伦指出的那样,你能做的是:
请注意,在第一种情况下,您无法通过从另一个构建函数调用来减少代码重复。您当然可以使用一个单独的private / protected方法来执行所有初始化,并让构造函数主要处理参数处理。
答案 7 :(得分:5)
在Visual C ++中,您还可以在构造函数中使用此表示法:this-&gt; 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 :(得分:4)
简单地说,你不能在C ++ 11之前。
C ++ 11引入了delegating constructors:
委派构造函数
如果类的名称本身在类中显示为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成员一次,并且只考虑一次,这是有道理的。
答案 9 :(得分:3)
尚未显示的另一个选项是将您的类拆分为两个,在您的原始类周围包装一个轻量级接口类,以实现您正在寻找的效果:
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 :(得分: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();
}
也就是说,而不是让一个构造函数调用另一个构造函数,它们都会调用私人朋友!
答案 11 :(得分:2)
这种方法可能适用于某些类(当赋值运算符表现得很好时):
Foo::Foo()
{
// do what every Foo is needing
...
}
Foo::Foo(char x)
{
*this = Foo();
// do the special things for a Foo with char
...
}
答案 12 :(得分:1)
如果我正确理解你的问题,你会问你是否可以在C ++中调用多个构造函数?
如果这就是你要找的东西,那么不 - 那是不可能的。
您当然可以拥有多个构造函数,每个构造函数都具有唯一的参数签名,然后在实例化新对象时调用所需的构造函数。
你甚至可以在最后有一个带有默认参数的构造函数。
但是你可能没有多个构造函数,然后分别调用它们。
答案 13 :(得分:1)
调用构造函数时,它实际上是从堆栈或堆中分配内存。因此,在另一个构造函数中调用构造函数会创建一个本地副本。所以我们正在修改另一个对象,而不是我们关注的对象。
答案 14 :(得分:0)
比测定更容易测试:) 试试这个:
#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
所以:)