《C++ Primer》第7章 类
7.5节 构造函数再探
struct X {
X (int i, int j): (base(i), rem(base % j) { }
int rem, base;
};
【出题思路】
struct X {
X (int i, int j): (base(i), rem(base % j) { }
int base, rem; //成员的初始化顺序与它们在类定义中的出现顺序一致:base比rem先初始化,这与构造函数初始值列表没有关系
};
Sales_data first_item(cin);
int main() {
Sales_data next;
Sales_data last("9-999-99999-9")
}
【出题思路】
Sales_data(std::istream &is = std::cin)
{
is >> *this;
}
此时该函数具有了默认构造函数的作用,因此我们原来声明的默认构造函数Sales_data() = default;应该去掉,否则会引起调用的二义性。
练习7.40:从下面的抽象概念中选择一个(或者你自己指定一个),思考这样的类需要哪些数据成员,提供一组合理的构造函数并阐明这样做的原因。
(a)Book (b)Date (c)Employee
(d)Vehicle (e)Object (f)Tree
【出题思路】
掌握创建类类型的方法,理解不同构造函数的区别。
【解答】
首先选择(a)Book,一本书通常包含书名、ISBN编号、定价、作者、出版社等信息,因此令其数据成员为:Name、ISBN、Price、Author、Publisher,其中Price是double类型,其他都是string类型。Book的构造函数有三个:一个默认构造函数、一个包含完整书籍信息的构造函数和一个接受用户输入的构造函数。其定义如下:
#include <iostream>
#include <string>
using namespace std;
class Book
{
//这里一定要重载>>操作符 否则Book(std::istream &is)会报
//invalid operands to binary expression('std::istream'(aka 'basic_istream<char>') and 'Book')的错误
friend std::istream& operator >> (std::istream&, Book&);
private:
string Name, ISBN, Author, Publisher;
double Price = 0;
public:
Book() = default;
Book(const string &n, const string &I, double pr, const string &a, const string &p)
{
Name = n;
ISBN = I;
Price = pr;
Author = a;
Publisher = p;
}
Book(std::istream &is)
{
is >> *this;
}
};
//接收5个参数
std::istream& operator >> (std::istream& in, Book& s)
{
in >> s.Name >> s.ISBN >> s.Author >> s.Publisher >> s.Price;
// check that the inputs succeeded
if (in)
{
cout << "Name==============" << s.Name << endl;
cout << "ISBN==============" << s.ISBN << endl;
cout << "Author============" << s.Author << endl;
cout << "Publisher=========" << s.Publisher << endl;
cout << "price=============" << s.Price << endl;
}
else
{
s = Book(); // input failed: reset object to default state
}
return in;
}
int main()
{
cout << "please input data====" << endl;
Book book(cin);
cout << "input finished===============" << endl;
return 0;
}
运行结果:
练习7.41:使用委托构造函数重新编写你的Sales_data类,给每个构造函数体添加一条语句,令期一量执行就打印一条信息。用千种可能的方式分别创建Sales_data对象,认真研究每次输出的信息直到你确实理解了委托构造函数的执行顺序。
【出题思路】
委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说它把它自己的一些或全部职责委托给了其他构造函数。程序先执行受委托构造函数,然后才执行委托构造函数本身的语句。
【解答】
改写后的Sales_data类及其验证程序如下所示:
#include <iostream>
#include <string>
using namespace std;
class Sales_data
{
friend std::istream &read(std::istream &is, Sales_data &item);
friend std::ostream &print(std::ostream &os, const Sales_data &item);
public:
Sales_data(const string &book, unsigned num, double sellp, double salep)
:bookNo(book), units_sold(num), sellingprice(sellp), saleprice(salep)
{
if(sellingprice)
discount = saleprice / sellingprice;
cout << "该构造函数接受书号、销售量、原价、实际售价四个信息" << endl;
}
Sales_data() : Sales_data("", 0, 0, 0)
{
cout << "该构造函数无须接受任何信息" << endl;
}
Sales_data(const string &book):Sales_data(book, 0, 0, 0)
{
cout << "该构造函数接受书号信息" << endl;
}
Sales_data(std::istream &is): Sales_data()
{
read(is, *this);
cout << "该构造函数接受用户输入的信息" << endl;
}
private:
std::string bookNo; //书籍编号,隐式初始化为空串
unsigned units_sold = 0; //销售量,显式初始化为0
double sellingprice = 0.0; //原始价格,显式初始化为0.0
double saleprice = 0.0; //实售价格,显式初始化为0.0
double discount = 0.0; //折扣,显式初始化为0.0
};
std::istream &read(std::istream &is, Sales_data &item)
{
is >> item.bookNo >> item.units_sold >> item.sellingprice >> item.saleprice;
return is;
}
std::ostream &print(std::ostream &os, const Sales_data &item)
{
os << item.bookNo << " " << item.units_sold << " " << item.sellingprice << " " << item.saleprice << " " << item.discount << endl;
return os;
}
int main()
{
cout << "第一个对象=========" << endl;
Sales_data first("987-7-121-15535-2", 85, 128, 109);
cout << "\n第二个对象=========" << endl;
Sales_data second;
cout << "\n第三个对象=========" << endl;
Sales_data third("987-7-121-15535-2");
cout << "\n第四个对象=========" << endl;
Sales_data last(cin);
return 0;
}
运行结果:
练习7.42:对于你在练习7.40(参见7.5.1节,第261页)中编写的类,确定哪些构造函数可以使用委托。如果可以的话,编写委托构造函数。如果不可以,从抽象概念列表中重新选择一个你认为可以使用委托构造函数的,为挑选出的这个概念编写类定义。
【出题思路】
委托构造函数是指使用它所属类的其他构造函数执行它自己的初始化过程,因此在类中应该设计一些构造函数使其具备自主的构造函数功能,而把另外一些设计成委托构造函数。
【解答】
以练习7.40构建的Book类为例,我们令其中的构造函数Book(const string &n,const string &I, double pr, const string &a, const string &p)为普通构造函数,而令另外两个作为委托构造函数。其具体形式如下所示:
#include <iostream>
#include <string>
using namespace std;
class Book
{
//这里一定要重载>>操作符 否则Book(std::istream &is)会报
//invalid operands to binary expression('std::istream'(aka 'basic_istream<char>') and 'Book')的错误
friend std::istream& operator >> (std::istream&, Book&);
private:
string Name, ISBN, Author, Publisher;
double Price = 0;
public:
Book(const string &n, const string &I, double pr, const string &a, const string &p)
{
Name = n;
ISBN = I;
Price = pr;
Author = a;
Publisher = p;
cout << "第一个构造函数=================" << endl;
}
Book() : Book("", "", 0, "", "")
{
cout << "第2个构造函数=================" << endl;
}
//Book(std::istream &is)
Book(std::istream &is): Book()
{
is >> *this;
}
void print()
{
cout << "Name = " << Name << "\nISBN = " << ISBN << "\nAuthor = " << Author << "\nPublisher = " << Publisher << endl;
}
};
//接收5个参数
std::istream& operator >> (std::istream& in, Book& s)
{
in >> s.Name >> s.ISBN >> s.Author >> s.Publisher >> s.Price;
// check that the inputs succeeded
if (in)
{
cout << "Name=======org=======" << s.Name << endl;
cout << "ISBN=======org=======" << s.ISBN << endl;
cout << "Author=====org=======" << s.Author << endl;
cout << "Publisher==org=======" << s.Publisher << endl;
cout << "price======org=======" << s.Price << endl;
}
else
{
s = Book(); // input failed: reset object to default state
}
return in;
}
int main()
{
cout << "please input data====" << endl;
Book book(cin);
cout << "input finished===============" << endl;
book.print();
return 0;
}
运行结果:
练习7.43:假定有一个名为NoDefault的类,它有一个接受int的构造函数,但是没有默认构造函数。定义类C,C有一个NoDefault类型的成员,定义C的默认构造函数。
【出题思路】
因为NoDefault仅有的一个构造函数并不是默认构造函数,所以在类C中,不能使用无参数的默认构造函数,那样的话,类C的NoDefault成员无法正确初始化。
【解答】
我们需要为类C的构造函数提供一个默认的int值作为参数,满足题意的类定义及验证程序如下所示:
#include <iostream>
#include <string>
using namespace std;
//该类型没有显式定义默认构造函数,编译器也不会为它合成一个
class NoDefault
{
public:
NoDefault(int i)
{
val = i;
cout << "NoDefault构造函数===========" << endl;
}
int val;
};
class C
{
public:
NoDefault nd;
//必须显式调用Nodefault的带参构造函数初始化nd
C(int i = 0): nd(i)
{
cout << "C构造函数===========" << endl;
}
};
int main()
{
C c; //使用了类型C的默认构造函数
cout << c.nd.val << endl;
return 0;
}
运行结果: