在这三种情况下,如何调用以下类的构造函数:全局对象,对象数组和另一个类/结构中包含的对象?
带有构造函数的类(在所有三个示例中使用):
class Foo {
public:
Foo(int a) { b = a; }
private:
int b;
};
以下是我尝试调用此构造函数的方法:
Foo global_foo(3); // works, but I can't control when the constructor is called.
int main() {
// ...
}
int main() {
// Array on stack
Foo array_of_foos[30](3); // doesn't work
// Array on heap
Foo *pointer_to_another_array = new Foo(3) [30]; // doesn't work
}
我试图为数组的所有元素调用构造函数,但我也想知道如何在单个元素上调用它。
class Bar {
Foo foo(3); // doesn't work
};
int main() {
Bar bar;
}
答案 0 :(得分:10)
你的唯一途径。另一方面,尽量避免这种情况。最好将函数(甚至其他对象)用作工厂。这样,您就可以控制创建时间。
没有办法直接这样做。非POD对象将始终默认构造。 std::fill
通常是一个很好的帮助。您可能还想查看分配器和std::uninitialized_fill
。
在构造函数中使用初始化列表:
class Bar {
Foo foo;
Bar() : foo(3) { }
};
实际上必须在类外部定义静态成员:
class Bar {
static Foo foo;
};
Foo Bar::foo(3);
答案 1 :(得分:4)
纠正一些关于全局变量的误解:
不是我推荐的东西但是:所以一个简单的解决方案是将所有全局变量放入一个编译单元。
或者你可以调整函数静态变量的使用 基本上你可以有一个函数返回你想要的全局引用(定义函数内的全局)。它将在首次使用时创建(并以与创建相反的顺序销毁)。
Foo& getGlobalA() // passed parameters can be passed to constructor
{
static Foo A;
return A;
}
Foo& getGlobalB()
{
static Foo B;
return B;
}
etc.
答案 2 :(得分:2)
Konrad的回复还可以,只是关于阵列的简单回复.... 有一种方法可以创建一个项目数组(而不是指针),下面是:
//allocate raw memory for our array
void *rawMemory = operator new[](30 * sizeof(Foo))
// point array_of_foos to this memory so we can use it as an array of Foo
Foo *array_of_foos = static_cast<Foo *>(rawMemory);
// and now we can create the array of objects(NOT pointers to the objects)
// using the buffered new operator
for (int i = 0; i < 30; i++)
new(array_of_foos[i])Foo(3);
答案 3 :(得分:1)
对于全局案例,无法控制何时调用它。 C ++规范基本上说它将在main()之前调用,之后会被销毁。除此之外'编译器可以随意使用。
在第一个数组中,您将创建一个Foo对象的静态数组。默认情况下,数组中的每个值都将使用Foo()的默认构造函数进行初始化。原始C ++数组无法强制调用特定的重载构造函数。您可以通过切换到向量而不是数组来推断出一些控制。向量构造函数有一个重载的构造函数向量(size,defaultValue),它应该可以实现你想要的。但在这种情况下你必须要小心,因为它不会调用Foo(3)而是调用Foo(const Foo&amp; other),其他的是Foo(3)。
第二个数组的情况与第一个案例非常相似。唯一真正的区别在于分配内存的位置(在堆而不是堆栈上)。它对调用构造函数有相同的限制。
所包含的案例是另一个问题。 C ++在对象内的字段定义和字段的初始化之间有明确的区分。要使其在C ++中工作,您需要将Bar定义更改为以下
class Bar{
Foo foo;
Bar() : foo(3){}
};
答案 4 :(得分:1)
在这个线程中似乎有一个通用要点,除了使用默认构造函数之外,你不能初始化数组的成员。一个答案甚至创建另一种类型,只是为了调用另一个构造函数。即使你可以(如果数组不属于类的成员!):
struct foo {
foo(int a): a(a) { }
explicit foo(std::string s): s(s) { }
private:
int a;
std::string s;
};
/* global */
foo f[] = { foo("global"), foo("array") };
int main() {
/* local */
foo f[] = { 10, 20, 30, foo("a"), foo("b") };
}
然而,类型需要是可复制的:给定的项目被复制初始化为数组的成员。
对于作为类成员的数组,目前最好使用容器:
struct bar {
/* create a vector of 100 foo's, initialized with "initial" */
bar(): f(100, foo("initial")) { }
private:
std::vector<foo> f;
};
使用andy.gurin描述的placement-new
技术也是一种选择。但请注意,这会使事情复杂化。您将不得不自己调用析构函数。如果任何构造函数抛出,而你仍在构建数组,那么你需要计算你停止的位置...总而言之,如果你想在你的类中有数组,并想要初始化它们,那么使用{{1这是一个简单的赌注。
答案 5 :(得分:0)
构建对象数组:
您可以使用默认参数修改原始示例。
目前仅支持默认构造函数 这是下一个版本正在解决的问题(因为每个人都会问这个问题)
答案 6 :(得分:0)
C ++ 0X初始化列表解决了对象数组的这个问题。请参阅this Herb Sutter博客文章,详细描述了这些内容。
与此同时,您可以像这样解决问题:
class Foo {
public:
Foo(int a) : b(a) {}
private:
int b;
};
class Foo_3 : public Foo {
public:
Foo_3() : Foo(3) {}
};
Foo_3 array_of_foos[30];
这里,Foo_3
类的存在仅仅是为了使用正确的参数调用Foo
构造函数。你甚至可以把它变成一个模板:
template <int i>
class Foo_n : public Foo {
public:
Foo_n() : Foo(i) {}
};
Foo_n<3> array_of_foos[30];
同样,这可能不会完全符合您的要求,但可能会提供一些思考的食物。
(另请注意,在你的Foo
课程中,您应该养成使用成员初始化列表而不是构造函数中的赋值的习惯,如上面的示例所示)
答案 7 :(得分:0)
我认为有两种方法可以确保在“创建”时安全地调用全局类对象的构造函数:
在命名空间中声明它们,并使该命名空间可全局访问。
使它成为一个指向类对象的全局指针,并在main()中为其指定一个新的类对象,为此访问该对象的其他全局对象的构造函数授予代码。
< / LI> 醇>只是我的两分钱。