如何为全局对象,对象数组以及类/结构体内的对象调用构造函数?

时间:2008-11-16 19:32:37

标签: c++ oop constructor

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

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

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

8 个答案:

答案 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)

纠正一些关于全局变量的误解:

  • 订单在编译单元中定义良好。
    • 与定义的顺序相同
  • 编译单元的顺序未定义。
  • 破坏的顺序是 EXACT 与创作相反。

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

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

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

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

答案 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)

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

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

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

    < / LI>

    只是我的两分钱。