第7章 类
7.1
#include "../ch02/ex2_42_sales_data.h"
int main()
{
Sales_data total;
if (std::cin >> total.bookNo >> total.units_sold >> total.revenue) {
Sales_data trans;
while (std::cin >> trans.bookNo >> trans.units_sold >> trans.revenue) {
if (total.bookNo == trans.bookNo)
total.AddData(trans);
else {
total.Print();
total = trans;
}
}
total.Print();
}
else {
std::cerr << "No data?!" << std::endl;
return -1;
}
return 0;
}
7.2
#ifndef CP5_ex7_02_h
#define CP5_ex7_02_h
#include <string>
// Add the combine and isbn members to the Sales_data
struct Sales_data {
std::string isbn() const { return bookNo; };
Sales_data& combine(const Sales_data&);
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
#endif
7.3
#include "ex7_02_sales_data.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
Sales_data total;
if (cin >> total.bookNo >> total.units_sold >> total.revenue) {
Sales_data trans;
while (cin >> trans.bookNo >> trans.units_sold >> trans.revenue) {
if (total.isbn() == trans.isbn())
total.combine(trans);
else {
cout << total.bookNo << " " << total.units_sold << " "
<< total.revenue << endl;
total = trans;
}
}
cout << total.bookNo << " " << total.units_sold << " " << total.revenue
<< endl;
}
else {
std::cerr << "No data?!" << std::endl;
return -1;
}
return 0;
}
7.4
//
// ex7_04.h
// Exercise 7.4
//
// Created by pezy on 14/11/8.
// Copyright (c) 2014 pezy. All rights reserved.
//
#ifndef CP5_ex7_04_h
#define CP5_ex7_04_h
#include <string>
class Person {
std::string name;
std::string address;
};
#endif
7.5
#ifndef CP5_ex7_05_h
#define CP5_ex7_05_h
#include <string>
class Person {
std::string name;
std::string address;
public:
const std::string& getName() const { return name; }
const std::string& getAddress() const { return address; }
};
#endif
参数列表后边的常数是指向常量的常数,有助于提高函数的灵活性。
7.6
#ifndef CP5_ex7_06_h
#define CP5_ex7_06_h
#include <iostream>
#include <string>
// added add, read, print functions
struct Sales_data {
std::string const& isbn() const { return bookNo; };
Sales_data& combine(const Sales_data&);
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
// member functions.
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// nonmember functions
std::istream& read(std::istream& is, Sales_data& item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& print(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
#endif
7.7
#include "ex7_06_sales_data.h"
int main()
{
Sales_data total;
if (read(std::cin, total)) {
Sales_data trans;
while (read(std::cin, trans)) {
if (total.isbn() == trans.isbn())
total.combine(trans);
else {
print(std::cout, total) << std::endl;
total = trans;
}
}
print(std::cout, total) << std::endl;
}
else {
std::cerr << "No data?!" << std::endl;
return -1;
}
return 0;
}
7.8
因为读操作中改变了item的数据成员revenue的值,而写操作并没有改变。
7.9
//
// ex7_09.h
// Exercise 7.9
//
// Created by pezy on 11/8/14.
// Copyright (c) 2014 pezy. All rights reserved.
//
#ifndef CP5_ex7_09_h
#define CP5_ex7_09_h
#include <string>
#include <iostream>
struct Person {
const std::string& getName() const { return name; }
const std::string& getAddress() const { return address; }
std::string name;
std::string address;
};
std::istream& read(std::istream& is, Person& person)
{
is >> person.name >> person.address;
if (!is) person = Person();
return is;
}
std::ostream& print(std::ostream& os, const Person& person)
{
os << person.name << " " << person.address;
return os;
}
#endif
7.10
if语句的条件将一次读取两个数据对象.
7.11
#ifndef CP5_ex7_11_h
#define CP5_ex7_11_h
#include <iostream>
#include <string>
// Add constructors to your Sales_data class
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(n * p)
{
}
Sales_data(std::istream& is);
std::string isbn() const { return bookNo; };
Sales_data& combine(const Sales_data&);
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
// nonmember functions
std::istream& read(std::istream& is, Sales_data& item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& print(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
// member functions.
Sales_data::Sales_data(std::istream& is)
{
read(is, *this);
}
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
#endif
#include "ex7_11_sales_data.h"
int main()
{
Sales_data item1;
print(std::cout, item1) << std::endl;
Sales_data item2("0-201-78345-X");
print(std::cout, item2) << std::endl;
Sales_data item3("0-201-78345-X", 3, 20.00);
print(std::cout, item3) << std::endl;
Sales_data item4(std::cin);
print(std::cout, item4) << std::endl;
}
7.12
#ifndef CP5_ex7_12_h
#define CP5_ex7_12_h
#include <iostream>
#include <string>
struct Sales_data;
std::istream& read(std::istream&, Sales_data&);
// Move the definition of the Sales_data constructor that takes an istream into
// the body of the Sales_data class.
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(n * p)
{
}
Sales_data(std::istream& is) { read(is, *this); }
std::string isbn() const { return bookNo; };
Sales_data& combine(const Sales_data&);
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
// member functions.
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// nonmember functions
std::istream& read(std::istream& is, Sales_data& item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& print(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
#endif
7.13
#include "ex7_12_sales_data.h"
int main()
{
Sales_data total(std::cin);
if (!total.isbn().empty()) {
std::istream& is = std::cin;
while (is) {
Sales_data trans(is);
if (total.isbn() == trans.isbn())
total.combine(trans);
else {
print(std::cout, total) << std::endl;
total = trans;
}
}
}
else {
std::cerr << "No data?!" << std::endl;
return -1;
}
return 0;
7.14
Sales_data():units_sold(0), revenue(0) {}
7.15
#ifndef CP5_ex7_15_h
#define CP5_ex7_15_h
#include <string>
#include <iostream>
struct Person;
std::istream& read(std::istream&, Person&);
struct Person {
Person() = default;
Person(const std::string sname, const std::string saddr)
: name(sname), address(saddr)
{
}
Person(std::istream& is) { read(is, *this); }
std::string getName() const { return name; }
std::string getAddress() const { return address; }
std::string name;
std::string address;
};
std::istream& read(std::istream& is, Person& person)
{
is >> person.name >> person.address;
return is;
}
std::ostream& print(std::ostream& os, const Person& person)
{
os << person.name << " " << person.address;
return os;
}
#endif
7.16
次数没有限制,访问说明符的有效范围直到出现下一个访问说明符或者到达类的结尾处为止。
定义在public说明符之后的成员在整个程序内可以被访问,定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问。
7.17
唯一区别是默认的访问权限,struct是public,class是private.
7.18
封装是实现与接口的分离,隐藏了类型的实现细节。通过将实现放在类的private中来实现的。
用处:
1.确保用户代码不会无意间破坏封装对象的状态。
2.被封装的类的具体实现细节可以随时改变,而无须调整用户级别的代码。
7.19
public:构造函数和部分成员函数:getName()
, getAddress()
private:数据成员和作为实现部分的函数name
, address
接口被定义为public,数据不应公开到类外部。
7.20
友元可以允许其他类或者函数访问它的非公有成员。
好处:
可以在类作用域中引用类成员,而不需要显式增加类名。 ??
方便访问所有私有成员
类用户更容易阅读
缺点:
减少封装,从而降低可维护性。
代码冗长,类内声明,类外声明。
7.21
#ifndef CP5_ex7_21_h
#define CP5_ex7_21_h
#include <iostream>
#include <string>
// Update Sales_data class to hide its implementation
class Sales_data {
friend std::istream& read(std::istream& is, Sales_data& item);
friend std::ostream& print(std::ostream& os, const Sales_data& item);
friend Sales_data add(const Sales_data& lhs, const Sales_data& rhs);
public:
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(n * p)
{
}
Sales_data(std::istream& is) { read(is, *this); }
std::string isbn() const { return bookNo; };
Sales_data& combine(const Sales_data&);
private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
// member functions.
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// friend functions
std::istream& read(std::istream& is, Sales_data& item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& print(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
#endif
7.22
#ifndef CP5_ex7_22_h
#define CP5_ex7_22_h
#include <string>
#include <iostream>
struct Person {
friend std::istream& read(std::istream& is, Person& person);
friend std::ostream& print(std::ostream& os, const Person& person);
public:
Person() = default;
Person(const std::string sname, const std::string saddr)
: name(sname), address(saddr)
{
}
Person(std::istream& is) { read(is, *this); }
std::string getName() const { return name; }
std::string getAddress() const { return address; }
private:
std::string name;
std::string address;
};
std::istream& read(std::istream& is, Person& person)
{
is >> person.name >> person.address;
return is;
}
std::ostream& print(std::ostream& os, const Person& person)
{
os << person.name << " " << person.address;
return os;
}
#endif
7.23
#ifndef CP5_ex7_23_h
#define CP5_ex7_23_h
#include <string>
class Screen {
public:
using pos = std::string::size_type;
Screen() = default;
Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c)
{
}
char get() const { return contents[cursor]; }
char get(pos r, pos c) const { return contents[r * width + c]; }
private:
pos cursor = 0;
pos height = 0, width = 0;
std::string contents;
};
#endif
7.24
#ifndef CP5_ex7_24_h
#define CP5_ex7_24_h
#include <string>
class Screen {
public:
using pos = std::string::size_type;
Screen() = default; // 1
Screen(pos ht, pos wd) : height(ht), width(wd), contents(ht * wd, ' ') {} // 2
Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c)
{
} // 3
char get() const { return contents[cursor]; }
char get(pos r, pos c) const { return contents[r * width + c]; }
private:
pos cursor = 0;
pos height = 0, width = 0;
std::string contents;
};
#endif
7.25
当类需要分配类对象之外的资源时,合成的版本常常会失效。
如果类包含vector或者string成员,则其拷贝,赋值和销毁的合成版本能够正常工作。
因此我们这个的内置类型和string可以依赖于拷贝和赋值操作的默认版本。
7.26
#ifndef CP5_ex7_26_h
#define CP5_ex7_26_h
#include <iostream>
#include <string>
// define Sales_data::avg_price as an inline function.
class Sales_data {
friend std::istream& read(std::istream& is, Sales_data& item);
friend std::ostream& print(std::ostream& os, const Sales_data& item);
friend Sales_data add(const Sales_data& lhs, const Sales_data& rhs);
public:
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(n * p)
{
}
Sales_data(std::istream& is) { read(is, *this); }
std::string isbn() const { return bookNo; };
Sales_data& combine(const Sales_data&);
private:
inline double avg_price() const;
private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
inline double Sales_data::avg_price() const
{
return units_sold ? revenue / units_sold : 0;
}
// declarations for nonmember parts of the Sales_data interface.
std::istream& read(std::istream& is, Sales_data& item);
std::ostream& print(std::ostream& os, const Sales_data& item);
Sales_data add(const Sales_data& lhs, const Sales_data& rhs);
#endif
7.27
#ifndef CP5_ex7_27_h
#define CP5_ex7_27_h
#include <string>
#include <iostream>
class Screen {
public:
using pos = std::string::size_type;
Screen() = default; // 1
Screen(pos ht, pos wd) : height(ht), width(wd), contents(ht * wd, ' ') {} // 2
Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c)
{
} // 3
char get() const { return contents[cursor]; }
char get(pos r, pos c) const { return contents[r * width + c]; }
inline Screen& move(pos r, pos c);
inline Screen& set(char c);
inline Screen& set(pos r, pos c, char ch);
const Screen& display(std::ostream& os) const
{
do_display(os);
return *this;
}
Screen& display(std::ostream& os)
{
do_display(os);
return *this;
}
private:
void do_display(std::ostream& os) const { os << contents; }
private:
pos cursor = 0;
pos height = 0, width = 0;
std::string contents;
};
inline Screen& Screen::move(pos r, pos c)
{
cursor = r * width + c;
return *this;
}
inline Screen& Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
inline Screen& Screen::set(pos r, pos c, char ch)
{
contents[r * width + c] = ch;
return *this;
}
#endif
7.28
只会改变临时量,不会改变myScreen.
7.29
#with '&'
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXX#XXXX
^^^
# without '&'
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXXXXXXX
^^^
7.30
优:更加明确,更少的误读
可使用与成员名称相同的成员函数参数。 ?p256
7.31
#ifndef CP5_ex7_31_h
#define CP5_ex7_31_h
class Y;
class X {
Y* y = nullptr;
};
class Y {
X x;
};
#endif
7.32
#ifndef CP5_ex7_32_h
#define CP5_ex7_32_h
#include <vector>
#include <string>
#include <iostream>
class Screen;
class Window_mgr {
public:
using ScreenIndex = std::vector<Screen>::size_type;
inline void clear(ScreenIndex);
private:
std::vector<Screen> screens;
};
class Screen {
friend void Window_mgr::clear(ScreenIndex);
public:
using pos = std::string::size_type;
Screen() = default; // 1
Screen(pos ht, pos wd) : height(ht), width(wd), contents(ht * wd, ' ') {} // 2
Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c)
{
} // 3
char get() const { return contents[cursor]; }
char get(pos r, pos c) const { return contents[r * width + c]; }
inline Screen& move(pos r, pos c);
inline Screen& set(char c);
inline Screen& set(pos r, pos c, char ch);
const Screen& display(std::ostream& os) const
{
do_display(os);
return *this;
}
Screen& display(std::ostream& os)
{
do_display(os);
return *this;
}
private:
void do_display(std::ostream& os) const { os << contents; }
private:
pos cursor = 0;
pos height = 0, width = 0;
std::string contents;
};
inline void Window_mgr::clear(ScreenIndex i)
{
if (i >= screens.size()) return; // judge for out_of_range.
Screen& s = screens[i];
s.contents = std::string(s.height * s.width, ' ');
}
inline Screen& Screen::move(pos r, pos c)
{
cursor = r * width + c;
return *this;
}
inline Screen& Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
inline Screen& Screen::set(pos r, pos c, char ch)
{
contents[r * width + c] = ch;
return *this;
}
#endif
7.33
Screen::pos Screen::size() const
{
return height*width;
}
7.34
编译不过,pos没有被声明。用来定义类型的成员必须先定义后使用。声明中使用的名字,包括返回类型或者参数列表中使用的名字,都必须在使用前确保可见。如果某个成员的生命使用了类中尚未出现的名字,则编译器将会在定义该类的作用于中继续查找。编译器只考虑就在使用类型之前出现的声明。
7.35
typedef string Type;
Type initVal(); // use `string`
class Exercise {
public:
typedef double Type;
Type setVal(Type); // use `double`
Type initVal(); // use `double`
private:
int val;
};
Type Exercise::setVal(Type parm) { // first is `string`, second is `double`
val = parm + initVal(); // Exercise::initVal()
return val;
}
因为当成员函数定义在类的外部时,返回类型中使用的名字都位于类的作用域之外。这时,返回类型必须指明它是哪个类的成员。--> Exercise::Type Exercise::setVal()
另外Exercise::initVal() should be defined.
7.36
rem先被初始化,而此时base还没有定义。
struct X {
X (int i, int j): base(i), rem(base % j) { }
int base, rem;
};
7.37
Sales_data first_item(cin); // use Sales_data(std::istream &is) ; its value are up to your input.
int main() {
Sales_data next; // use Sales_data(std::string s = ""); bookNo = "", cnt = 0, revenue = 0.0
Sales_data last("9-999-99999-9"); // use Sales_data(std::string s = ""); bookNo = "9-999-99999-9", cnt = 0, revenue = 0.0
}
7.38
Sales_data(std::istream &is = std::cin) { read ( is , *this) ; }
7.39
违法的。因为重载“sales_data()”的调用不明确。
7.40
class Book {
public:
Book() = default;
Book(unsigned no, std::string name, std::string author, std::string pubdate) : no_(no), name_(name), author_(author), pubdate_(pubdate) { }
Book(std::istream &in) { in >> no_ >> name_ >> author_ >> pubdate_; }
private:
unsigned no_;
std::string name_;
std::string author_;
std::string pubdate_;
};
7.41
头文件:ex7_41_sales_data.h
#ifndef CP5_ex7_41_h
#define CP5_ex7_41_h
#include <iostream>
#include <string>
// use delegating constructors, added a statement to the body of each of the
// constructors that prints a message whether it is executed
class Sales_data {
friend std::istream& read(std::istream& is, Sales_data& item);
friend std::ostream& print(std::ostream& os, const Sales_data& item);
friend Sales_data add(const Sales_data& lhs, const Sales_data& rhs);
public:
Sales_data(const std::string& s, unsigned n, double p)
: bookNo(s), units_sold(n), revenue(n * p)
{
std::cout << "Sales_data(const std::string&, unsigned, double)"
<< std::endl;
}
Sales_data() : Sales_data("", 0, 0.0f)
{
std::cout << "Sales_data()" << std::endl;
}
Sales_data(const std::string& s) : Sales_data(s, 0, 0.0f)
{
std::cout << "Sales_data(const std::string&)" << std::endl;
}
Sales_data(std::istream& is);
std::string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
private:
inline double avg_price() const;
private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
inline double Sales_data::avg_price() const
{
return units_sold ? revenue / units_sold : 0;
}
// declarations for nonmember parts of the Sales_data interface.
std::istream& read(std::istream& is, Sales_data& item);
std::ostream& print(std::ostream& os, const Sales_data& item);
Sales_data add(const Sales_data& lhs, const Sales_data& rhs);
#endif
库文件:ex7_41_sales_data.cpp
#include "ex7_41_sales_data.h"
// constructor
Sales_data::Sales_data(std::istream& is) : Sales_data()
{
std::cout << "Sales_data(istream &is)" << std::endl;
read(is, *this);
}
// member functions.
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// friend functions
std::istream& read(std::istream& is, Sales_data& item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
std::ostream& print(std::ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
main文件:
#include "ex7_41_sales_data.h"
using std::cout;
using std::endl;
int main()
{
cout << "1. default way: " << endl;
cout << "----------------" << endl;
Sales_data s1;
cout << "\n2. use std::string as parameter: " << endl;
cout << "----------------" << endl;
Sales_data s2("CPP-Primer-5th");
cout << "\n3. complete parameters: " << endl;
cout << "----------------" << endl;
Sales_data s3("CPP-Primer-5th", 3, 25.8);
cout << "\n4. use istream as parameter: " << endl;
cout << "----------------" << endl;
Sales_data s4(std::cin);
return 0;
}
// print
/*
* 1. default way:
* ----------------
* Sales_data(const std::string&, unsigned, double)
* Sales_data()
*
* 2. use std::string as parameter:
* ----------------
* Sales_data(const std::string&, unsigned, double)
* Sales_data(const std::string&)
*
* 3. complete parameters:
* ----------------
* Sales_data(const std::string&, unsigned, double)
*
* 4. use istream as parameter:
* ----------------
* Sales_data(const std::string&, unsigned, double)
* Sales_data()
* Sales_data(istream &is)
*
*/
7.41
class Book {
public:
Book(unsigned no, std::string name, std::string author, std::string pubdate):no_(no), name_(name), author_(author), pubdate_(pubdate) { }
Book() : Book(0, "", "", "") { }
Book(std::istream &in) : Book() { in >> no_ >> name_ >> author_ >> pubdate_; }
private:
unsigned no_;
std::string name_;
std::string author_;
std::string pubdate_;
};
7.42
class Book {
public:
Book(unsigned no, std::string name, std::string author, std::string pubdate):no_(no), name_(name), author_(author), pubdate_(pubdate) { }
Book() : Book(0, "", "", "") { }
Book(std::istream &in) : Book() { in >> no_ >> name_ >> author_ >> pubdate_; }
private:
unsigned no_;
std::string name_;
std::string author_;
std::string pubdate_;
};
7.43
#include <vector>
class NoDefault {
public:
NoDefault(int i) {}
};
class C {
public:
C() : def(0) {} // define the constructor of C.
private:
NoDefault def;
};
int main()
{
C c;
std::vector<C> vec(10);
return 0;
}
7.44
非法,因为有十个元素,每个元素都会被初始化。但没有no default类型的默认构造函数。
7.45
是没有问题的。因为C有默认构造函数。
7.46
(1) 不正确。编译器会生成构造函数,称为合成的默认构造函数。
(2)不正确,默认构造函数是在未提供初始值设定项时使用的构造函数。此外,为其所有参数提供默认参数的构造函数也定义了默认构造函数。
(3) 不正确,类应该提供。
(4) 不正确,只有当我们的类没有显式定义任何构造函数时,编译器才会隐式定义我们的默认构造函数。
7.47
是否需要从string到sales_data的转换依赖于我们对用户使用该转换的看法。在此例中,这种转化可能是对的。null_book中的string可能表示了一个不存在的ISBN编号。
优点:
1.抑制构造函数定义的隐式转换。
2.可以定义一个只能使用直接初始化形式的构造函数
缺点:只对一个实参的构造函数有效
7.48
都正确。都是调用构造函数,没有发生隐式类型转换。
7.49
(a)合法。用s自动创建一个临时Sales_data对象,传递给combine.
(b)不合法。不可以把一个临时量绑定在一个普通引用上。
(c)不合法。参数列表后边的const会使得不能改变其数据成员,会造成冲突。
7.50
explicit Person(std::istream& is) { read(is, *this); }
7.51
比如:
int getSize(const std::vector<int>&);
如果不是explicit,可以这样使用
getSize(34);
是混乱的。
但是std::string是不同的,我们使用std::string替代const char*,比如
void setYouName(std::string); //declaration
setYourName("pezy")
7.52
题目应该为
struct Sales_data {
std::string bookNo;
unsigned units_sold;
double revenue;
};
7.53
#ifndef CP5_ex7_53_h
#define CP5_ex7_53_h
class Debug {
public:
constexpr Debug(bool b = true) : rt(b), io(b), other(b) {}
constexpr Debug(bool r, bool i, bool o) : rt(r), io(i), other(0) {}
constexpr bool any() { return rt || io || other; }
void set_rt(bool b) { rt = b; }
void set_io(bool b) { io = b; }
void set_other(bool b) { other = b; }
private:
bool rt; // runtime error
bool io; // I/O error
bool other; // the others
};
#endif
7.54
不应该,因为constexpr函数必须正好包含一个返回语句.
7.55
不是,因为string不是一个字面值类型。
7.56
类的静态成员是与类本身直接相关的类的成员,而不是与类的各个对象保持关联。
优点:每个对象不需要存储一个共同的数据,若果数据被更改,每个对象都可以使用新的值。
静态成员与普通成员区别:
1.静态数据成员可以是不完全类型。
2.可以使用静态成员作为默认参数。
7.57
#ifndef CP5_ex7_57_h
#define CP5_ex7_57_h
#include <string>
class Account {
public:
void calculate() { amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double newRate) { interestRate = newRate; }
private:
std::string owner;
double amount;
static double interestRate;
static constexpr double todayRate = 42.42;
static double initRate() { return todayRate; }
};
double Account::interestRate = initRate();
#endif
7.58
若一定要在类内初始化静态成员,必须满足:
1)静态成员必须是字面值常量类型的constexpr。
字面值类型就是通常遇到的:算术类型,引用,指针等。字面值常量类型就是const型的算术类型,引用,指针等。
2)给静态成员提供的初始值,必须为常量表达式.
static double rate = 6.5;
^
rate必须是常量表达式
static vector<double> vec(vecSize);
^
错误!vector是模板不是字面值常量类型,所以不满足第一条。应该改为 static vector<double> vec; //仅仅且只能进行声明,不能定义
// example.h
class Example {
public:
static constexpr double rate = 6.5;
static const int vecSize = 20;
static vector<double> vec;
};
// example.C
#include "example.h"
constexpr double Example::rate;
vector<double> Example::vec(Example::vecSize);