2010-05-30 97 views
0

我试图在类中实例化一个类,以便外部类包含内部类。在一个类中实例化一个类

这是我的代码:

#include <iostream> 
#include <string> 

class Inner { 
    private: 
     std::string message; 

    public: 
     Inner(std::string m); 
     void print() const; 
}; 

Inner::Inner(std::string m) { 
    message = m; 
} 

void Inner::print() const { 
    std::cout << message << std::endl; 
    std::cout << message << std::endl; 
} 

class Outer { 
    private: 
     std::string message; 
     Inner in; 

    public: 
     Outer(std::string m); 
     void print() const; 
}; 

Outer::Outer(std::string m) { 
    message = m; 
} 

void Outer::print() const { 
    std::cout << message << std::endl; 
} 

int main() { 
    Outer out("Hello world."); 
    out.print(); 

    return 0; 
} 

“内在的”,是我在含内内尝试外,然而,当我编译,我得到一个错误,有呼叫没有匹配功能到Inner :: Inner()。 我做错了什么?

谢谢。

回答

6

您需要使用初始化列表来初始化类成员:

Inner::Inner(const std::string& m) 
    : message(m) 
{ 
} 

Outer::Outer(const std::string& m) 
    : in(m) 
{ 
} 

(请注意,我通过每const参考,这比按值传递他们更好的琴弦见this answer如何通过。函数参数)。

这样,您可以准确指定应为类成员调用哪些构造函数。

如果你没有指定一个构造函数,默认的将被隐式调用。随后分配给对象然后将调用赋值运算符并覆盖默认构造函数初始化对象的内容。这是浪费表现充其量。
由于我们Inner没有默认构造函数(声明任何构造防止编译器本身定义了默认的构造函数),它不能被调用,所以你需要到指定构造以字符串明确。


编辑:需要注意的是,如果你有一个以上的类的成员,他们都初始化的方式,以逗号分隔:

Outer::Outer(const std::string& m) : in1(m), in2(m), in3() {} 

注意的初始化顺序班级成员由班级定义中的申报顺序决定,而不是按它们在初始化列表中出现的顺序。最好不要依赖初始化顺序,因为在类定义中更改它会在构造函数的定义中创建一个非常微妙的错误。如果无法避免,加注释除了类成员声明:

class outer { 
    public: 
    outer(const inner& in) 
    : in_(in), rin_(in_) // depends on proper declaration order of in_ and rin_ 
    {} 
    private: 
    inner in_; // declaration order matters here!1 
    inner& rin_; // (see constructor for details) 
}; 

基类的构造函数指定了同样的方式,他们是类成员初始化之前,同样在声明的顺序基类列表。然而,虚拟基类在所有非虚拟基类之前被初始化。


析构函数,顺便说一句,总是按照与构造函数相反的顺序调用。你可以依靠这一点。

+0

谢谢!我设法弄清楚了这一点。 – 2010-05-30 12:03:13

+0

-1。你不需要使用初始化列表来初始化类成员。问题是缺少的默认构造函数。有几种方法可以解决这个问题 - 使用初始化程序列表,在其中传递Inner字段的初始值只是一个。 – iheanyi 2014-07-29 15:42:30

+1

@iheanyi:为了解决上述问题,您需要。否则'Inner'不会有初始化的数据成员。另外,我的类通常不会显示默认构造函数。这是因为对于我的很多类来说,初始化但数据不足的状态是没有意义的。 YMMV,但添加默认构造函数只是为了避免在初始化列表中列出数据成员对我来说似乎是一个非常错误的建议。 – sbi 2014-07-30 04:56:11

1

由于Inner没有默认构造函数,所以需要显式初始化它。正如@sbi所指出的,这样做的方式是使用构造函数中的初始化列表。

+0

或者他可以创建一个默认构造函数。 – iheanyi 2014-07-29 15:43:04

-1

你也可以添加一个构造函数给Inner,不带任何参数。由于您没有明确初始化inOuter,所以隐含地试图调用它。如果in是一个指针(Inner *in),那么它会工作。

基本上,如果你用C++写的

Foo f; 

,它会调用默认的构造函数(Foo::Foo())。

+0

但是,它会首先默认 - 初始化对象只是立即用赋值运算符覆盖该值。对不起,但国际海事组织这是不好的建议,最好使用初始化列表来指定正确的构造函数。 -1从我。 – sbi 2010-05-30 11:59:38

+0

哦,那是真的。只是想指出这也是可能的(并且通常可能需要)。 – 2010-05-30 12:09:38

+0

+1 @sbi也许在这个特定的情况下,它会。但作为一般规则,使用默认构造函数是一个适当的问题,不一定是坏事。 – iheanyi 2014-07-29 15:45:38