7.1
#include <iostream>
#include <vector>
using namespace std;
struct Sales_data
{
std::string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
};
int main()
{
Sales_data info;
Sales_data temp;
while (cin >> info.bookNo >> info.units_sold >> info.revenue)
{
if (temp.bookNo.empty())
{
temp = info;
}
else if (info.bookNo == temp.bookNo)
{
temp.units_sold += info.units_sold;
temp.revenue += info.revenue;
}
else {
cout << "bookNo:" << temp.bookNo << " units_sold:" << temp.units_sold << " revenue:" << temp.revenue << endl;
temp = info;
}
}
cout << "bookNo:" << temp.bookNo << " units_sold:" << temp.units_sold << " revenue:" << temp.revenue << endl;
return 0;
}
7.2
#include <iostream>
#include <vector>
using namespace std;
struct Sales_data
{
string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
double price = 0.0;//单价
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
price = revenue / units_sold;
return *this;
}
7.3
#include <iostream>
#include <vector>
using namespace std;
struct Sales_data
{
string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
double price = 0.0;//单价
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
price = revenue / units_sold;
return *this;
}
int main()
{
Sales_data info;
Sales_data temp;
while (cin >> info.bookNo >> info.units_sold >> info.revenue)
{
info.price = info.revenue / info.units_sold;
if (temp.bookNo.empty())
{
temp = info;
}
else if (info.isbn() == temp.isbn())
{
temp.combine(info);
}
else {
cout << "bookNo:" << temp.bookNo << " units_sold:" << temp.units_sold << " revenue:" << temp.revenue << " price:" << temp.price << endl;
temp = info;
}
}
cout << "bookNo:" << temp.bookNo << " units_sold:" << temp.units_sold << " revenue:" << temp.revenue << " price:" << temp.price << endl;
return 0;
}
7.4
struct Person
{
string Name;//姓名
string adress;//住址
};
7.5
应是const,因其只需读取,无需改变;
struct Person
{
string Name;//姓名
string Adress;//住址
string get_Name() const { return Name; }
string get_Adress() const { return Adress; }
};
7.6 & 7.7
#include <iostream>
#include <vector>
using namespace std;
struct Sales_data
{
string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price()const;
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
double Sales_data::avg_price()const
{
if (units_sold)
{
return revenue / units_sold;
}
else {
return 0;
}
}
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;
}
ostream& print(ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
int main()
{
Sales_data info;
Sales_data temp;
while (read(cin,info))
{
if (temp.bookNo.empty())
{
temp = info;
}
else if (info.isbn() == temp.isbn())
{
temp=add(info, temp);
}
else {
print(cout,temp);
temp = info;
}
}
print(cout, temp);
return 0;
}
7.8
read函数需改变成员对象;
print函数无需改变成员对象;
7.9
#include <iostream>
#include <vector>
using namespace std;
struct Person
{
string Name;//姓名
string Adress;//住址
string get_Name() const { return Name; }
string get_Adress() const { return Adress; }
};
istream &Read(istream &is, Person &item)
{
is >> item.Name >> item.Adress;
return is;
}
ostream& Print(ostream& os, const Person& item)
{
os << item.get_Name() <<" " << item.get_Adress();
return os;
}
7.10
读入data1和data2并判断是否为真;
7.11
#include <iostream>
using namespace std;
struct Sales_data
{
//构造函数
Sales_data() = default;
Sales_data(string& s) :bookNo(s) {}
Sales_data(string& s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p* n) {}
Sales_data(istream&);
//其他成员
string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price()const;
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
double Sales_data::avg_price()const
{
if (units_sold)
{
return revenue / units_sold;
}
else {
return 0;
}
}
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;
}
ostream& print(ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
Sales_data::Sales_data(istream& is)
{
read(is, *this);
}
int main()
{
Sales_data exp0;
print(cout, exp0) << endl;
string str = "0001";
Sales_data exp1(str);
print(cout, exp1) << endl;
str = "0002";
Sales_data exp2(str, 5, 10.5);
print(cout, exp2) << endl;
Sales_data exp3(cin);
print(cout, exp3) << endl;
}
7.12
#include <iostream>
using namespace std;
struct Sales_data;
istream& read(std::istream& is, Sales_data& item);
struct Sales_data
{
//构造函数
Sales_data() = default;
Sales_data(string & s) :bookNo(s) {}
Sales_data(string & s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p * n) {}
Sales_data(istream & is) { read(is, *this); }
//其他成员
string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price()const;
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
double Sales_data::avg_price()const
{
if (units_sold)
{
return revenue / units_sold;
}
else {
return 0;
}
}
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;
}
ostream& print(ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
//Sales_data::Sales_data(istream& is)
//{
// read(is, *this);
//}
int main()
{
Sales_data exp0;
print(cout, exp0) << endl;
string str = "0001";
Sales_data exp1(str);
print(cout, exp1) << endl;
str = "0002";
Sales_data exp2(str, 5, 10.5);
print(cout, exp2) << endl;
Sales_data exp3(cin);
print(cout, exp3) << endl;
}
7.13
int main()
{
Sales_data total(cin);
if (!total.isbn().empty())
{
Sales_data trans;
while (read(cin, trans))
{
if (total.isbn() == trans.isbn())
{
total.combine(trans);
}
else
{
print(cout, total) << endl;
total = trans;
}
}
print(cout, total) << endl;
}
else {
cerr << "No Data?!" << endl;
}
return 0;
}
7.14
Sales_data() : bookNo(string()), units_sold(0), revenue(0.0) { }
7.15
#include <iostream>
using namespace std;
struct Person;
istream& Read(istream& is, Person& item);
ostream& Print(ostream& os, const Person& item);
struct Person
{
Person() = default;
Person(string& s) :Name(s) {}
Person(string& s0, string& s1) :Name(s0), Adress(s1) {}
Person(istream& is) { Read(is, *this); }
string Name;//姓名
string Adress;//住址
string get_Name() const { return Name; }
string get_Adress() const { return Adress; }
};
istream& Read(istream& is, Person& item)
{
is >> item.Name >> item.Adress;
return is;
}
ostream& Print(ostream& os, const Person& item)
{
os << item.get_Name() << " " << item.get_Adress();
return os;
}
7.16
一个类可以包含0个或多个访问说明符,而且对于某个访问说明符能出现多少次也没有严格规定;
如果某个成员需要在整个程序内都被访问,那么它应该定义为 public; 如果某个成员只能在类内部访问,那么它应该定义为 private。
7.17
使用class和struct定义类唯一的区别就是默认的访问权限:
使用class默认访问权限:private;
使用struct默认访问权限:public。
7.18
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问成员变量private,提供对应的getXxx()/setXxx()方法。
通过方法来控制成员变量的操作,提高了代码的安全性;把代码用方法进行封装,提高了代码的复用性。
7.19
class Person
{
friend istream& Read(istream& is, Person& item);
public:
Person() = default;
Person(string & s) :Name(s) {}
Person(string & s0, string & s1) :Name(s0), Adress(s1) {}
Person(istream & is) { Read(is, *this); }
string get_Name() const { return Name; }
string get_Adress() const { return Adress; }
private:
string Name;//姓名
string Adress;//住址
};
构造函数、getName()、getAddress() 函数将设为 public。name 和 address 将设为private。
函数是暴露给外部的接口,因此要设为public;而数据则应该隐藏让外部不可见。
7.20
访问非公有成员时有用;
利:与当前类有关的接口函数能直接访问类的私有变量。
弊:破坏了封装性。
7.21
#include <iostream>
using namespace std;
class Sales_data;
istream& read(std::istream& is, Sales_data& item);
ostream& print(ostream&, const Sales_data&);
Sales_data add(const Sales_data&, const Sales_data&);
class Sales_data
{
friend istream& read(istream&, Sales_data&);
friend ostream& print(ostream&, const Sales_data&);
friend Sales_data add(const Sales_data&, const Sales_data&);
public:
Sales_data() = default;
Sales_data(string& s) :bookNo(s) {}
Sales_data(string& s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p* n) {}
Sales_data(istream& is) { read(is, *this); }
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
private:
string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
double avg_price()const;
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
double Sales_data::avg_price()const
{
if (units_sold)
{
return revenue / units_sold;
}
else {
return 0;
}
}
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;
}
ostream& print(ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
7.22
#include <iostream>
using namespace std;
class Person;
istream& Read(istream& is, Person& item);
ostream& Print(ostream& os, const Person& item);
class Person
{
friend istream& Read(istream&, Person&);
friend ostream& Print(ostream&, const Person&);
public:
Person() = default;
Person(string & s) :Name(s) {}
Person(string & s0, string & s1) :Name(s0), Adress(s1) {}
Person(istream & is) { Read(is, *this); }
string get_Name() const { return Name; }
string get_Adress() const { return Adress; }
private:
string Name;//姓名
string Adress;//住址
};
istream& Read(istream& is, Person& item)
{
is >> item.Name >> item.Adress;
return is;
}
ostream& Print(ostream& os, const Person& item)
{
os << item.get_Name() << " " << item.get_Adress();
return os;
}
7.23&&7.24
#include <iostream>
using namespace std;
class Screen
{
public:
using pos = string::size_type;
Screen() = default;
Screen(pos ht, pos wd) :height(ht), width(wd), contents(ht * wd, ' ') {}
Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht * wd, c) {}
char get()const { return contents[cursor]; }
inline char get(pos r, pos c) const;
private:
pos cursor = 0;
pos height = 0, width = 0;
string contents;
};
char Screen::get(pos r, pos c)const
{
pos row = r * width;
return contents[row + c];
}
7.25
能,
Screen 的成员只有内置类型和 string,因此能安全地依赖于拷贝和赋值操作的默认版本。管理动态内存的类则不能依赖于拷贝和赋值操作的默认版本,而且也应该尽量使用string 和 vector 来避免动态管理内存的复杂性。
7.26
class Sales_data
{
friend istream& read(istream&, Sales_data&);
friend ostream& print(ostream&, const Sales_data&);
friend Sales_data add(const Sales_data&, const Sales_data&);
public:
Sales_data() = default;
Sales_data(string& s) :bookNo(s) {}
Sales_data(string& s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p* n) {}
Sales_data(istream& is) { read(is, *this); }
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
private:
string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
inline double avg_price()const;
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
double Sales_data::avg_price()const
{
if (units_sold)
{
return revenue / units_sold;
}
else {
return 0;
}
}
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;
}
ostream& print(ostream& os, const Sales_data& item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
return os;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
7.27
#include <iostream>
using namespace std;
class Screen
{
public:
using pos = string::size_type;
Screen() = default;
Screen(pos ht, pos wd) :height(ht), width(wd), contents(ht* wd, ' ') {}
Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht* wd, c) {}
char get()const { return contents[cursor]; }
inline char get(pos r, pos c) const;
Screen& move(pos r, pos c);
Screen& set(char);
Screen& set(pos, pos, char);
Screen& display(ostream& os) { os << contents; return*this; }
private:
pos cursor = 0;
pos height = 0, width = 0;
string contents;
};
char Screen::get(pos r, pos c)const
{
pos row = r * width;
return contents[row + c];
}
Screen& Screen::move(pos r, pos c)
{
pos row = r * width;
cursor = row + c;
return *this;
}
inline Screen& Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
inline Screen& Screen::set(pos r, pos col, char ch)
{
contents[r * width + col] = ch;
return *this;
}
int main()
{
Screen myScreen(5, 5, 'X');
myScreen.move(4, 0).set('#').display(cout);
cout << "\n";
myScreen.display(cout);
cout << "\n";
}
7.28
返回类型是Screen的输出:
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXXXXXXX
当返回类型不使用引用时,move、set和display返回的是Screen的临时副本,操作并不会改变myScreen。
7.29
正确
7.30
优点:
1:程序的意图更明确。当需要将一个对象作为整体引用而不是引用对象的一个成员时,使用this,则该函数返回对调用该函数的对象的引用。
2:可以非常明确地指出访问的是调用该函数的对象的成员,且可以在成员函数中使用与数据成员同名的形参。
缺点:有时候显得有点多余。
7.31
class Y;
class X {
Y* y = nullptr;
};
class Y {
X x;
};
7.32
#include <iostream>
#include <vector>
using namespace std;
class Screen;
class Window_mgr;
class Screen
{
friend class Window_mgr;
public:
using pos = string::size_type;
Screen() = default;
Screen(pos ht, pos wd) :height(ht), width(wd), contents(ht* wd, ' ') {}
Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht* wd, c) {}
char get()const { return contents[cursor]; }
inline char get(pos r, pos c) const;
Screen& move(pos r, pos c);
Screen& set(char);
Screen& set(pos, pos, char);
Screen& display(ostream& os) { os << contents; return*this; }
private:
pos cursor = 0;
pos height = 0, width = 0;
string contents;
};
class Window_mgr {
public:
using ScreenIndex = std::vector<Screen>::size_type;
void clear(ScreenIndex);
private:
vector<Screen> screens{ Screen(24,80,' ') };
};
char Screen::get(pos r, pos c)const
{
pos row = r * width;
return contents[row + c];
}
Screen& Screen::move(pos r, pos c)
{
pos row = r * width;
cursor = row + c;
return *this;
}
inline Screen& Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
inline Screen& Screen::set(pos r, pos col, char ch)
{
contents[r * width + col] = ch;
return *this;
}
void Window_mgr::clear(ScreenIndex i)
{
Screen s = screens[i];
s.contents = string(s.height * s.width, ' ');
}
7.33
未定义标识符 pos
Screen::pos Screen::size()const
{
return height * width;
}
7.34
在该类作用域内使用pos的地方显示:未定义标识符“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(Type parm) { // first is `double`, second is `double`
val = parm + initVal(); // Exercise::initVal()
return val;
}
7.36
成员初始化顺序和类中定义的顺序一致,故先初始化rem,后初始化base,初始化rem需要用到base,故程序报错;
struct X {
X (int i, int j): base(i), rem(base % j) {}
int base, rem;
};
7.37
Sales_data first_item(cin); // 使用 Sales_data(std::istream &is) ; 各成员值从输入流中读取
int main() {
Sales_data next; // 使用默认构造函数 bookNo = "", cnt = 0, revenue = 0.0
Sales_data last("9-999-99999-9"); // 使用 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
非法,重载Sale_data()将不明确;
7.40
#include <iostream>
using namespace std;
class Employee
{
public:
Employee() = default;
Employee(istream& is) { is >> name >> age >> adress; }
Employee(string n, int ag, string ad) :name(n), age(ag), adress(ad) {}
private:
string name;
int age;
string adress;
};
7.41
class Sales_data
{
friend istream& read(istream&, Sales_data&);
friend ostream& print(ostream&, const Sales_data&);
friend Sales_data add(const Sales_data&, const Sales_data&);
public:
Sales_data(string s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p* n) { cout << "Sales_data(string s, unsigned n, double p)" << endl; }
Sales_data() :Sales_data("", 0, 0) { cout << "Sales_data()" << endl; }
Sales_data(string s) :Sales_data(s, 0, 0) { cout << "Sales_data(string s)" << endl; }
Sales_data(istream& is):Sales_data() { read(is, *this);cout << "Sales_data(istream& is)" << endl; }
string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
private:
string bookNo;
unsigned units_sold = 0;//销量
double revenue = 0.0;//收入
inline double avg_price()const;
};
7.42
#include <iostream>
using namespace std;
class Employee
{
public:
Employee(string n, int ag, string ad) :name(n), age(ag), adress(ad) {}
Employee() :Employee("",0,"") {}
Employee(istream& is) { is >> name >> age >> adress; }
private:
string name;
int age;
string adress;
};
7.43
class NoDefault
{
public:
NoDefault(int num) {}
};
class c
{
public:
c() :nodefault(0) {}
private:
NoDefault nodefault;
};
7.44
非法,NoDefault 没有默认构造函数。
7.45
合法,C 有默认构造函数。
7.46
(a)正确,如果我们的类没有显式地定义构造函数,那么编译器就会为我们隐式地定义一个默认构造函数,并称之为合成的默认构造函数。
(b)不正确,为每个参数都提供了默认值的构造函数也是默认构造函数。
©不正确,哪怕没有意义的值也需要初始化。
(d)不正确,只有当一个类没有显式定义任何构造函数的时候,编译器才会生成一个默认构造函数;引用和指针数据成员没有合成默认构造函数。
7.47
都可以,取决于我们对用户使用该转换的看法。
P264原文:是否需要从string到sales_data的转换依赖于我们对用户使用该转换的看法。在此例中,这种转化可能是对的。null_book中的string可能表示了一个不存在的ISBN编号。
优点:
- 可以抑制构造函数定义的隐式转换;
- 可以定义一个只能使用直接初始化形式的构造函数;
缺点:
- 只对一个实参的构造函数有效;
7.48
无影响,调用构造函数,未发生隐式类型转换。
7.49
- (a) string隐式类型转换为Sales_data,传入临时量副本;
- (b) 错误:无法将string隐式转换为Sales_data&,combine的参数时非常量的引用,我们不能将临时参数传递给它,改为:Sales_data &combine(const Sales_data&);
- © 错误,string隐式转换为Sales_data,传给常量引用,但常量成员函数不能改变 this。
7.50
explicit Person(string & s) :Name(s) {}
explicit Person(istream & is) { Read(is, *this); }
7.51
比如:
int getSize(const std::vector<int>&);
如果不是explicit
,可以这样使用
getSize(34);
是混乱的。
而string
则不同,string
的单参数构造函数的参数是const char *
,因此凡是在需要用到string
的地方都可以用const char *
来代替(字面值就是const char *
)。如:
void print(std::string);
print("hello world");
7.52
错误,Sales_data
类不是聚合类,不能使用显式地初始化类的对象。
需要把Sales_data
类,改为聚合类:
struct Sales_data {
std::string bookNo;
unsigned units_sold;
double revenue;
};
7.53
class Debug {
public:
constexpr Debug(bool b = true) : hw(b), io(b), other(b) { }
constexpr Debug(bool h, bool i, bool o) : hw(h), io(i), other(0) { }
constexpr bool any() { return hw || io || other; }
void set_hw(bool b) { hw = b; }
void set_io(bool b) { io = b; }
void set_other(bool b) { other = b; }
private:
bool hw;
bool io;
bool other;
};
7.54
不能,constexpr函数有限制:1)函数返回类型及所有形参地类型必须是字面值类型;2)必须有且只有一条返回语句;
在c++11中,constexpr函数不能改变数据成员,c++14中没有这个特点;
7.55
不是
std::string 不是字面值类型。
#include <string>
#include <iostream>
#include <type_traits>
struct Data {
int ival;
std::string s;
};
int main()
{
std::cout << std::boolalpha;
std::cout << std::is_literal_type<Data>::value << std::endl;
// output: false
}
7.56
类的静态成员与类本身直接相关,而不是与类的各个对象相互关联;
但是我们仍然可以使用类作用域运算符访问静态成员,加上static关键字即可声明;
每个对象不需要存储公共数据,如果数据被改变,则每个对象都可以使用新值;
静态成员与普通成员区别:
- 静态数据成员可以是不完全型;
- 可以使用静态成员作为默认实参;
7.57
class Account {
public:
void calculate() { amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double);
private:
std::string owner;
double amount;
static double interestRate;
static double initRate() { return 0; };
};
void Account::rate(double newRate)
{
interestRate = newRate;
}
double Account::interestRate = initRate();
7.58
通常情况下,类的静态成员不应该在类的内部初始化。然而,
- 我们可以为静态成员提供
const
整数类型的类内初始值,不过要求静态成员必须是字面值常量类型的constexpr
; - 初始值必须是常量表达式,因为这些成员本身就是常量表达式,所以它们能用在所有适合于常量表达式的地方。
// example.h
class Example {
public:
static constexpr double rate = 6.5;//rate改为常量表达式
static const int vecSize = 20;
static vector<double> vec;//vector是模板不是字面值常量类型,故只能声明,不能被初始化。
};
// example.C
#include "example.h"
constexpr double Example::rate;
vector<double> Example::vec(Example::vecSize);