12

在这三种情况下,您将如何调用以下类的构造函数:全局对象、对象数组和包含在另一个类/结构中的对象?

具有构造函数的类(在所有三个示例中都使用):

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;
}
4

8 回答 8

11

全局对象

你的方法是唯一的。另一方面,尽量避免这种情况。最好将函数(甚至其他对象)用作工厂。这样,您可以控制创建时间。

对象数组

没有办法直接做到这一点。非 POD 对象将始终是默认构造的。std::fill往往是很大的帮助。您可能还想研究分配器和std::uninitialized_fill.

类/结构中包含的对象

在构造函数中使用初始化列表:

class Bar {
    Foo foo;

    Bar() : foo(3) { }
};

静态成员实际上必须在类之外定义:

class Bar {
    static Foo foo;
};

Foo Bar::foo(3);
于 2008-11-16T19:39:42.017 回答
5

为了纠正对全局变量的一些误解:

  • 该顺序在编译单元中得到了很好的定义。
    • 与定义顺序相同
  • 跨编译单元的顺序未定义。
  • 毁灭的顺序与创造完全相反。

不是我推荐的东西,但是:所以一个简单的解决方案是将所有全局变量放入一个编译单元中。

或者,您可以调整函数静态变量的使用。
基本上你可以有一个函数返回对你想要的全局的引用(在函数内部定义全局)。它将在首次使用时创建(并以创建的相反顺序销毁)。

Foo& getGlobalA() // passed parameters can be passed to constructor
{
    static Foo  A;
    return A;
}
Foo& getGlobalB()
{
    static Foo  B;
    return B;
}
etc. 
于 2008-11-16T20:04:01.983 回答
3

Konrad 的回复是好的,只是关于数组的一个 puntualization.... 有一种方法可以创建一个项目数组(不是指针),如下所示:

//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);

这种方法在这里描述:http ://www.amazon.com/gp/product/0321334876?ie=UTF8&tag=aristeia.com-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0321334876

于 2008-11-16T20:10:09.443 回答
2

对于全局情况,无法控制何时调用。C++ 规范本质上说它将在 main() 之前调用,并在之后的某个时间被销毁。除此之外,编译器可以随心所欲地做任何事情。

在第一个数组案例中,您正在创建一个 Foo 对象的静态数组。默认情况下,数组中的每个值都将使用 Foo() 的默认构造函数进行初始化。原始 C++ 数组无法强制调用特定的重载构造函数。您可以通过切换到向量而不是数组来推断出一些控制。向量构造函数有一个重载的构造函数 vector(size,defaultValue) 应该实现你正在寻找的东西。但在这种情况下,您必须小心,因为它不会调用 Foo(3),而是调用 Foo(const Foo& other),其中 other 是 Foo(3)。

第二种数组情况与第一种情况非常相似。唯一真正的区别是分配内存的位置(在堆上而不是在堆栈上)。它在调用构造函数方面具有相同的限制。

包含的案例是一个不同的问题。C++ 在对象内字段的定义和字段的初始化之间有明确的区分。要让它在 C++ 中工作,您需要将 Bar 定义更改为以下

class Bar{
  Foo foo;
  Bar() : foo(3){}
};
于 2008-11-16T19:40:10.893 回答
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;
};

使用placement-newandy.gurin 描述的技术也是一种选择。但请注意,这会使事情复杂化。您必须自己调用析构函数。如果任何构造函数抛出,而你仍在构建数组,那么你需要弄清楚你停止的位置......总而言之,如果你想在你的类中有数组,并且想要初始化它们,使用 astd::vector很简单赌注。

于 2008-11-16T22:31:24.727 回答
0

对象数组的构造:

您可以使用默认参数修改原始示例。

目前仅支持默认构造函数。
这是下一个版本正在解决的问题(因为每个人都会问这个问题)

于 2008-11-16T20:10:47.787 回答
0

C++0X 初始化列表为对象数组解决了这个问题。请参阅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课程中,您确实应该养成使用成员初始化列表而不是构造函数中的赋值的习惯,如我上面的示例所示)

于 2008-11-16T20:34:57.957 回答
0

我认为有两种方法可以确保在“创建”时安全地调用全局类对象的构造函数:

  1. 在命名空间中声明它们并使该命名空间可全局访问。

  2. 使其成为指向类对象的全局指针,并在 main() 中为其分配一个新的类对象,授予访问该对象的其他全局对象的构造函数的代码将在此之前执行。

只是我的两分钱。

于 2011-03-29T23:43:58.783 回答