Sales_data类
#include <string>
#include <iostream>
class Sales_data {
friend std::ostream& print(std::ostream&, const Sales_data&);
friend std::istream& read(std::istream&, Sales_data&);
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(p* n) {}
Sales_data(std::istream&);
std::string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
private:
double avg_price() const;
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream& print(std::ostream&, const Sales_data&);
std::istream& read(std::istream&, Sales_data&);
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;
}
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 << " " << 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(std::istream& is) {
read(is, *this);
}
类的其他特性
class Screen{
public:
typedef std::string::size_type pos;
Screen() = default;
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 ht,pos wd) const;
Screen& move(pos r,pos c);
private:
pos cursor = 0;
pos height = 0,width = 0;
std::string contents;
};
inline char get(pos ht,pos wd) const{
pos row = r * width;
return contents[row + c];
}
inline Screen& move(pos r,pos c){
pos row = r * width;
cursor = row + c;
return *this;
}
可变数据成员
class Screen{
public:
void some_member() const;
private:
mutable size_t access_ctr;
};
void Screen::some_member() const{
++access_ctr;
}
类数据成员的初始值
class Window_mgr{
private:
std::vector<Screen> screens{Screen(24,80,' ')};
};
返回*this的成员函数
class Screen{
public:
Screen& set(char);
Screen& set(pos,pos,char);
};
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;
}
Screen myScreen;
myScreen.display(cout).set('#');
基于const的重载
class Screen{
public:
Screen& display(std::ostream& os){do_display(os);return *this;}
const Screen& display(std::ostream& os){do_display(os);return *this;
private:
void do_display(std::ostream& os) const{os<<contents;}
}
};
Screen myScreen(5,3);
const Screen blank(5,3);
myScreen.set('#').display(cout);
blank.display(cout);
类类型
- 两个类,即使他们成员完全一样,这两个类也是两个不同的类型。
- 允许类包含指向它自身类型的引用或指针。
class Link_screen{
Screen window;
Link_screen *next;
Link_screen *prev;
};
深入友元
- 类可把其他类定义成友元,也可把其他类的成员函数定义成友元。
- 友元函数能定义在类的内部,这样的函数是隐式内联的。
- 友元不具有传递性
class Screen{
friend class Window_mgr;
};
class Window_mgr{
public:
using ScreenIndex = std::vector<Screen>::size_type;
void clear(ScreenIndex);
private:
std::vector<Screen> screens{Screen(24,80,' ')};
};
void Window_mgr::clear(ScreenIndex i){
Screen& s = screens[i];
s.contents = string(s.height * s.width,' ');
}
类的作用域
class Window_mgr{
public:
ScreenIndex addScreen(const Screen&);
};
Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen& s){
screens.push_back(s);
return screen.size()-1;
}
名字查找与类的作用域
typedef double Money;
string bal;
class Account{
public:
Money balance(){return bal;}
private:
Money bal;
};
typedef double Money;
class Account{
public:
Money balance(){return bal;}
private:
typedef double Money;
Money bal;
};
成员定义中的普通块作用域的名字查找
int height;
class Screen{
public:
typedef std::string::size_type pos;
void dummy_fcn(pos height){
cursor = width * height;
}
private:
pos cursor = 0;
pos height = 0,width = 0;
};
void Screen::dummy_fcn(pos height){
cursor = width * this->height;
}
void Screen::dummy_fcn(pos ht){
cursor = width * height;
}
void Screen::dummy_fcn(pos height){
cursor = width * ::height;
}
构造函数再探
构造函数初始值列表
Sales_data::Sales_data(const string& s,unsigned cnt,double price){
bookNo = s;
units_sold = cnt;
revenue = cnt * price;
}
class ConstRef{
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
};
ConstRef::ConstRef(int ii){
i = ii;
ci = ii;
ri = i;
}
ConstRef::ConstRef(int ii):i(ii),ci(ii),ri(i){}
成员初始化的顺序
- 最好令构造函数初始值的顺序与成员声明的顺序保持一致,且尽量避免使用某些成员初始化其他成员
- 成员初始化的顺序与它们在类定义中的出现顺序一致。
默认实参和构造函数
class Sales_data{
public:
Sales_data(std::string s = ""):bookNo(s){}
Sales_data(std::string s,unsigned cnt,double rev):bookNo(s),units_sold(cnt),revenue(rev*cnt){}
Sales_data(std::istream& is){read(is,*this);}
};
委托构造函数
class Sales_data{
public:
Sales_data(std::string s,unsigned cnt,double price):bookNo(s),units_sold(cnt),revenue(cnt*price){}
Sales_data():Sales_data("",0,0){}
Sales_data(std::string s):Sales_data(s,0,0){}
Sales_data(std::istream& is):Sales_data(){read(is,*this);}
};
隐式的类型转换
- 如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制。这种构造函数又叫转换构造函数(converting constructor)。
string null_book = "99999";
item.combine(null_book);
item.combine("9999");
item.combine(string("99999"));
item.combine(Sales_data("9999"));
item.combine(cin);
抑制构造函数定义的隐式转换
class Sales_data{
public:
Sales_data() = default;
Sales_data(const string& s,unsigned n,double p):bookNo(s),units_sold(cnt),revenue(p*n){}
explicit Sales_data(const std::string& s):bookNo(s){}
explicit Sales_data(std::istream&);
};
//将构造函数声明为explicit阻止隐式转换
item.combine(null_book);
item.combine(cin);//这两个都将无法通过编译
//explicit只对一个实参的构造函数有效。需要多个实参的构造函数不能用于执行隐式转换,
//也就无需指定为explicit,类内声明,类外不应重复。
explicit构造函数只能用于直接初始化
Sales_data item1(null_book);
Sales_data item2 = null_book;
为转换显式地使用构造函数
- 尽管编译器不会将explicit的构造函数用于隐式转换过程,但是我们可以使用这样的构造函数显式地强制进行转换
item.combine(Sales_data(null_book));
item.combine(static_cast<Sales_data>(cin));
- 标准库中接受一个单参数的const char*的string构造函数不是explicit的。接受一个容量参数的vector构造函数是explicit的。
聚合类
struct Data{
int ival;
string s;
};
Data val1 = {0,"Anan"};
- 所有成员都是public的。没有定义任何构造函数。没有类内初始值。没有基类,也没有virtual函数。
可以使用一个花括号括起来的成员初始值列表,初始值的顺序必须和声明的顺序一致。
字面值常量类
- constexpr函数的参数和返回值必须是字面值。
- 字面值类型:除了算术类型、引用和指针外,某些类也是字面值类型。
- 数据成员都是字面值类型的聚合类是字面值常量类。
- 如果不是聚合类,则必须满足下面所有条件:
- 数据成员都必须是字面值类型。
- 类必须至少含有一个constexpr构造函数。
- 如果一个数据成员含有类内部初始值,则内置类型成员的初始值必须是一条常量表达式;或者如果成员属于某种类类型,则初始值必须使用成员自己的constexpr构造函数。
- 类必须使用析构函数的默认定义,该成员负责销毁类的对象。
类的静态成员
class Accout{
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();
};
- 类的静态成员存在于对象之外,对象中不包含任何与静态数据成员有关的数据。不能用this指针,不能声明成const。
使用类的静态成员
double r;
r = Account::rate();
Account ac1;
Account *ac2 = &ac1;
r = ac1.rate();
r = ac2->rate();
定义静态成员
- 既可以在类内部也可在外部定义静态成员,外部定义时不能重复static关键字
void Account::rate(double newRate){
interestRate = newRate;
}
double Account::interestRate = initRate();
class Account{
private:
static constexpr int period = 30;
double daily_tbl[period];
};
静态成员能用于某些场景,普通成员不能
class Bar{
public:
private:
static Bar mem1;
Bar *mem2;
Bar mem3;
};
class Screen{
public:
Screen& clear(char = bkground);
private:
static const char bkground;
};
class Example {
public:
static constexpr double rate = 6.5;
static const int vecSize = 20;
static vector<double> vec;
};
#include "example.h"
constexpr double Example::rate;
vector<double> Example::vec(Example::vecSize);