2

阅读 Andrew Koenig 和 Barbara E. Moo 的“Accelerated C++”的另一个问题,我在关于构造函数(5.1)的章节,使用前面的例子。

他们写

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

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

将实际工作委托给 read 函数。[...] read 立即赋予这些变量新的值。

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类下的函数,为什么还要使用第二个构造函数——这不是双重工作吗?为什么不只使用默认构造函数,然后使用函数,因为两者都已经定义了?

4

2 回答 2

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 的主要目标之一是编写可重用而非自我重复的代码,另一个目标是关注点分离。在许多情况下,实例化对象的人不需要知道类的实现细节。

在您的示例read函数上,当它在构造函数中调用时,它可以是私有的。这给我们带来了 OOP封装的另一个概念

最后,这不是双重工作,它是软件设计的好方法

于 2013-03-22T07:33:03.570 回答
1

我的问题是,既然 read 已经被定义为 Student_info 类下的一个函数,为什么还需要使用第二个构造函数——这不是双重工作吗?

第二个构造函数从调用者那里获取一个参数并将其传递给read函数。这允许您直接Student_info用实例化 a std::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...

为什么不只使用默认构造函数,然后使用函数,因为两者都已经定义了?

因为最好构造对象,使它们处于连贯的、有用的状态,而不是先构造它们,然后再初始化它们。这意味着对象的用户不必担心对象是否可以使用或必须先初始化。例如,此函数引用 a 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不必担心对象已“初始化”或生效。

于 2013-03-22T07:17:23.967 回答