Andrew Koenig和Barbara E. Moo阅读“Accelerated C ++”的另一个问题,我在关于构造函数(5.1)的章节中,使用示例before。
他们写
我们要定义两个构造函数:第一个构造函数不带参数并创建一个空的
Student_info
对象;第二个引用输入流并通过从该流中读取学生记录来初始化对象。
导致使用Student_info::Student_info(istream& is) {read(is);}
作为第二个构造函数
将实际工作委托给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
类下的函数,为什么需要使用第二个构造函数 - 这不是双重工作吗?为什么不使用默认构造函数,然后使用函数,因为两者都已定义?
答案 0 :(得分: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
最后,这不是双重工作,也是软件设计的好方法
答案 1 :(得分:1)
我的问题是,因为read已经被定义为Student_info类下的一个函数,为什么需要使用第二个构造函数 - 这不是双重工作吗?
第二个构造函数从调用者获取一个参数并将其传递给read
函数。这允许您使用Student_info
直接实例化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...
为什么不使用默认构造函数,然后使用函数,因为两者都已定义?
因为构造对象使它们处于连贯,有用的状态更好,而不是先构造它们然后初始化它们。这意味着对象的用户不必担心是否可以使用该东西或必须首先初始化该东西。例如,此函数引用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
不应该担心对象已被“初始化”或有效。