2013-03-22 341 views
2

Andrew Koenig和Barbara E. Moo阅读“Accelerated C++”的另一个问题,我在关于构造函数的章节(5.1)中,使用before这个例子。带参数的构造函数初始化

他们写

我们要定义两个构造函数:第一个构造函数没有参数,并创建一个空的Student_info对象;第二个参考输入流并通过从该流读取学生记录来初始化该对象。

导致使用Student_info::Student_info(istream& is) {read(is);}作为第二构造的例子

代表实际工作的读取功能。读取立即给这些变量新值。

Student_info

class Student_info { 
public: 
    std::string name() const (return n;} 
    bool valid() const {return !homework.empty();} 
    std::istream& read(std::istream&); 

    double grade() const; 
private: 
    std::string n; 
    double midterm, final; 
    std::vector<double> homework; 
}; 

由于read已经被定义为Student_info类下的函数,为什么有必要使用第二个构造 - 这不就是双重的工作?为什么不使用默认构造函数,然后函数,因为两者都已经定义?

回答

1

我的问题是,因为read已被定义为Student_info类下的函数,为什么需要使用第二个构造函数 - 是不是这个双重工作?

第二个构造函数从调用方获取参数并将其传递给read函数。这允许你直接实例化Student_infostd::istream

std::istream is = ....; 
Student_info si(is); // internally calls read(is) 

,而不是

std::istream is = ....; 
Student_info si; 
si.read(is);  // how could we use is if this call isn't made? Now we have to read some docs... 

为什么不直接使用默认的构造函数,然后因为这两个功能都已经定义?

因为最好是构造一个对象,使它们处于一个连贯的有用状态,而不是先构造它们然后初始化它们。这意味着对象的用户不必担心事物是否可以使用或者必须首先被初始化。例如,该功能需要一个Student_info参考:

void foo(const Student_into& si) 
{ 
    // we want to use si in a way that might require that it has been 
    // initialized with an istream 
    si.doSomethingInvolvingInputStream(); // Wait, what if the stream hasn't been read in? 
             // Now we need a means to check that! 
} 

理想的情况下,foo不应该担心的对象已经被“初始化”或有效。

+0

所以它保存初始化所有的变量(他们的零版本)的步骤之前它写完了吗? 有没有速度/功率差异,还是只是为了清晰? – sccs 2013-03-22 07:22:02

+1

@sccs变量首先被初始化,因为函数是从构造函数的主体中调用的。在这个阶段,所有的数据成员都已经构建完成。所以真正的原因是我在最后一段中提到的设计方面。这不仅仅是清晰度:一种在施工后必须明确初始化的类型是非常没用的(尽管我每天都在工作中遇到它们) – juanchopanza 2013-03-22 07:23:44

+0

我刚刚看到了,谢谢!还有一个 - 是否存在没有第二个构造函数(带参数)的程序? – sccs 2013-03-22 07:24:55

5

这不是相反双重的工作,它简化了如果你创建类的单个构造每次你有时间做

std::istream is = std::cin; 
Student_info si(); 
si.read(is); 
// si.foo(); 
// si.bar(); 
// si.baz(); 
谁实例化类

来电的对象初始化

也许可以添加一些可以在构造函数中完成的其他操作。所以当你需要实例化类的时候,你不必再写它们。如果创建10个实例,你将不得不写

(10 -1 =)9条线,这是不适合OOP

Student_info::Student_info(istream& is) 
{ 
    read(is); 
    //foo(); 
    //bar(); 
    //baz(); 
} 

一个很好的做法,但一旦你定义像上面两个构造函数,你可以使用类像

std::istream is = std::cin; 
Student_info si(is); 

之一的OOP的编写可重用的主要目标,而不是自我重复的代码,另一个目标是seperation of concerns。在很多情况下,实例化对象的人不需要知道类的实现细节。

在你的例子read函数可以是私人的,当它调用内部构造函数。这达到我们OOP的另一个概念Encapsulation

最后,这不是双重的工作及其对软件设计的一个很好的办法