Sales_data total; if(read(cin, total)) { Sales_data trans; while(read(cin, trans)) { if(total.isbn() == trans.isbn()) { total.conbine(trans); } else { print(cout, total) << endl; total = trans; } } print(cout, total) << endl; } else { cerr << "No data?!" << endl; }
这是定义重写过的数据读取的类。
在该代码的第一行,生命了一个对象,但是并没有对对象进行赋值。
并且对于对象类型而言,我们也不知道该如何对其内容进行初始化赋值。
而未赋值的对象是否会在使用的时候产生问题?
如何对对象进行自定义的初始化赋值?
其实在对象声明的时候编译器会默认调用一个函数,它叫做构造函数
这个函数的名称与类名相同,没有返回值类型。
在没有定义的情况下,编译器会自动添加一个空的构造函数。
当有任意构造函数的时候这个默认构造函数将被去掉。
接下来我们来为Sales_item定义构造函数。
struct Sales_data { Sales_data() = default; Sales_data(const std::string &s) : bookNo(s){} Sales_data(const std::string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p*n){} Sales_data(std::istream &); // 以上全部为构造函数 std::string isbn() const {return bookNo;} // 直接定义在类内部的函数是隐式inline的函数 Sales_data& combine(const Sales_data&); double avg_price() const; std::string booNo; unsigned units_sold = 0; double revenue = 0.0; };
Sales_data::Sales_data(std::istream & is)
{
read(is, *this);
}
=default
C++11的新特性
这个关键字使用在构造上述上意味着,要求编译器按照默认的方式来构造这个构造函数。
即在类型中没有构造函数时,编译器添加的构造函数完全一致
初始化类表
Sales_data(const std::string &s) : bookNo(s){} Sales_data(const std::string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p*n){}
在上面的代码中,出现了函数声明后双信号后面部分的内容,我们称为初始化列表。
初始化列表的作用在于以初始化的形式来进行变量的值改变,而不是赋值的方式,所以效率要高。
拷贝、赋值和析构
以上描述的这几种函数在程序员未明确声明的时候编译器都会提供默认的版本。
在类型作为参数或返回值调用的过程中会调用拷贝函数。
在调用=号的时候会调用赋值函数。
而在对象销毁的时候会调用到析构函数。
对于不存在自控制的动态内存的类型来说默认的已经够用了。
但是如果存在动态内存的调用则需要自己定义,这个定义的方法将会在后面详细讲解。