第二章
C++算术类型
C++标准规定的尺寸最小值,编译器被允许赋予这些类型更大的尺寸。
2.3
C++Primer第五版习题集的答案如下,已在VS2019中进行了测试。
2.5
- 补充:一些前缀后缀
012是一个八进制数,对应着十进制的10;
0xC是十六进制数,对应着十进制的12;
10e-2是一个浮点数,使用了科学计数法表示,大小为10*10-2=0.1
2.8
- 转义序列如图
#include<stdio.h>
#include<iostream>
#include"Sales_item.h"
using namespace std;
int main()
{
cout << "2M\n";
cout << "2\tM\n";
return 0;
}
使用cout << "\x4d";
也可以输出M。
2.11
2.23
2.24
void*是一种特殊的指针类型,可以存放任意对象的地址。
2.30
顶层const:指针本身是一个常量
底层const:指针所指的对象是一个常量
执行对象的拷贝操作的时候,顶层const不受什么影响,拷入和拷出的对象必须具有相同的底层const资格。
2.35
auto一般会忽略掉顶层const,同时底层const会被保留。
如果希望得到的auto类型是顶层const,需要明确指出const auto = ……
2.36
decltype类型指示符:选择并返回操作数的数据类型。
如果使用的表达式不是一个变量,那么decltype返回表达式结果对应的类型:例如如果表达式是一个解引用操作,则得到引用类型。
2.37
赋值是一种会产生引用的类型表达式。
2.40
struct Sales_data
{
std::string bookNo;//书籍编号
unsigned units_sold = 0;//销售量
double sellingprice = 0.0;//零售价
double saleprice = 0.0;//实售价
double discount = 0.0;//折扣
double revenue = 0.0;//销售收入
};
2.41
#include<iostream>
#include<string>
using namespace std;
class Sales_data
{
//运算符重载
//友元函数
friend std::istream& operator >> (std::istream&, Sales_data&);
//友元函数
friend std::ostream& operator << (std::ostream&, const Sales_data&);
//友元函数
friend bool operator < (const Sales_data&, const Sales_data&);
//友元函数
friend bool operator == (const Sales_data&, const Sales_data&);
public://三种形式的构造函数
Sales_data() = default;
Sales_data(const std::string& book) :bookNo(book) {}
Sales_data(std::istream& is) { is >> *this; }
public:
Sales_data& operator += (const Sales_data&);
std::string isbn() const { return bookNo; }
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
};
inline bool compareIsbn(const Sales_data& lhs, const Sales_data& rhs)
{
return lhs.isbn() == rhs.isbn();
}
Sales_data operator + (const Sales_data&, const Sales_data&);
inline bool operator == (const Sales_data& lhs, const Sales_data& rhs)
{
return lhs.units_sold == rhs.units_sold &&
lhs.sellingprice == rhs.sellingprice &&
lhs.saleprice == rhs.saleprice &&
lhs.isbn() == rhs.isbn();
}
inline bool operator != (const Sales_data& lhs, const Sales_data& rhs)
{
return !(lhs == rhs);//基于运算符==给出!=定义
}
Sales_data& Sales_data::operator += (const Sales_data& rhs)
{
units_sold += rhs.units_sold;
saleprice = (rhs.saleprice * rhs.units_sold + saleprice * units_sold) / (rhs.units_sold + units_sold);
if (sellingprice != 0)
{
discount = saleprice / sellingprice;
}
return *this;
}
Sales_data operator + (const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret(lhs);//把lhs的内容拷贝到临时变量ret中,便于运算
ret += rhs;
return ret;
}
std::istream& operator>>(std::istream& in, Sales_data& s)
{
in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
if (in && s.sellingprice != 0)
{
s.discount = s.saleprice / s.sellingprice;
}
else {
s = Sales_data();//输入错误,重置输入的数据
}
return in;
}
std::ostream& operator<<(std::ostream& out, const Sales_data& s)
{
out << s.isbn() << " " << s.units_sold << " " << s.sellingprice << " " << s.saleprice << " " << s.discount;
return out;
}
int main()
{
Sales_data book;
std::cout << "请输入销售记录:ISBN 售出本数 原始价格 实售价格 " << std::endl;
while (std::cin >> book) {
std::cout << "ISBN 售出本数 原始价格 实售价格 折扣为:\n" << book << std::endl;
}
Sales_data trans1, trans2;
std::cout << "请输入两条相同ISBN的销售记录:" << std::endl;
std::cin >> trans1 >> trans2;
if (compareIsbn(trans1, trans2))
{
std::cout << "汇总信息:ISBN 售出本数 原始价格 实售价格 折扣为:\n" << trans1 + trans2 << std::endl;
}
else {
std::cout << "两条销售记录的ISBN不同" << std::endl;
}
Sales_data total, trans;
std::cout << "请输入几条ISBN相同的销售记录" << std::endl;
if (std::cin >> total) {
while (std::cin >> total)
{
if (compareIsbn(total, trans))//ISBN相同
total = total + trans;
else {
//ISBN不同
std::cout << "当前书籍ISBN不同" << std::endl;
break;
}
}
std::cout << "有效汇总信息: ISBN 售出本数 原始价格 实售价格 折扣为:\n" << total << std::endl;
}
else
{
std::cout << "没有数据" << std::endl;
return -1;
}
int num = 1;//记录当前书籍的销售记录总数
std::cout << "请输入若干销售记录:" << std::endl;
if (std::cin >> trans1)
{
while (std::cin >> trans2)
{
if (compareIsbn(trans1, trans2))//ISBN相同
num++;
else {
//ISBN不同
std::cout << trans1.isbn() << "共有" << num << "条销售记录" << std::endl;
trans1 = trans2;
num = 1;
}
}
std::cout << total.isbn() << "共有" << num << "条销售记录" << std::endl;
}
else {
std::cout << "没有数据" << std::endl;
return -1;
}
return 0;
}
- 2.41中发现的问题
while (std::cin >> book) {
std::cout << "ISBN 售出本数 原始价格 实售价格 折扣为:\n" << book << std::endl;
}
此处输入一次以后Enter不会退出循环,要求继续输入。然后使用Ctrl+Z虽然退出循环,但是后面所有的输入流都不会再执行。
解决:在后面的while输入循环前,加了个cin.clear();对cin标志位进行复位。即改为如下代码:
while (std::cin >> book) {
std::cout << "ISBN 售出本数 原始价格 实售价格 折扣为:\n" << book << std::endl;
}
std::cin.clear();
参考了以下博客:
C++:关于cin输入ctrl+Z之后不能再用问题的原因
2.42
预处理变量无视C++中关于作用域的规则。
- Sales_data.h头文件中的内容是:
#ifndef SALES_DATA_H_INCLUDED
// we're here only if SALESDATA_H has not yet been defined
#define SALES_DATA_H_INCLUDED
// Definition of Sales_item class and related functions goes here
#include<iostream>
#include<string>
class Sales_data
{
//运算符重载
//友元函数
friend std::istream& operator >> (std::istream&, Sales_data&);
//友元函数
friend std::ostream& operator << (std::ostream&, const Sales_data&);
//友元函数
friend bool operator < (const Sales_data&, const Sales_data&);
//友元函数
friend bool operator == (const Sales_data&, const Sales_data&);
public://三种形式的构造函数
Sales_data() = default;
Sales_data(const std::string& book) :bookNo(book) {}
Sales_data(std::istream& is) { is >> *this; }
public:
Sales_data& operator += (const Sales_data&);
std::string isbn() const { return bookNo; }
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
};
inline bool compareIsbn(const Sales_data& lhs, const Sales_data& rhs)
{
return lhs.isbn() == rhs.isbn();
}
Sales_data operator + (const Sales_data&, const Sales_data&);
inline bool operator == (const Sales_data& lhs, const Sales_data& rhs)
{
return lhs.units_sold == rhs.units_sold &&
lhs.sellingprice == rhs.sellingprice &&
lhs.saleprice == rhs.saleprice &&
lhs.isbn() == rhs.isbn();
}
inline bool operator != (const Sales_data& lhs, const Sales_data& rhs)
{
return !(lhs == rhs);//基于运算符==给出!=定义
}
Sales_data& Sales_data::operator += (const Sales_data& rhs)
{
units_sold += rhs.units_sold;
saleprice = (rhs.saleprice * rhs.units_sold + saleprice * units_sold) / (rhs.units_sold + units_sold);
if (sellingprice != 0)
{
discount = saleprice / sellingprice;
}
return *this;
}
Sales_data operator + (const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret(lhs);//把lhs的内容拷贝到临时变量ret中,便于运算
ret += rhs;
return ret;
}
std::istream& operator>>(std::istream& in, Sales_data& s)
{
in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
if (in && s.sellingprice != 0)
{
s.discount = s.saleprice / s.sellingprice;
}
else {
s = Sales_data();//输入错误,重置输入的数据
}
return in;
}
std::ostream& operator<<(std::ostream& out, const Sales_data& s)
{
out << s.isbn() << " " << s.units_sold << " " << s.sellingprice << " " << s.saleprice << " " << s.discount;
return out;
}
#endif
- main.cpp源文件的内容是:
#include<iostream>
#include<string>
#include"Sales_data.h"
int main()
{
Sales_data book;
std::cout << "请输入销售记录:ISBN 售出本数 原始价格 实售价格 " << std::endl;
while (std::cin >> book) {
std::cout << "ISBN 售出本数 原始价格 实售价格 折扣为:\n" << book << std::endl;
}
std::cin.clear();
Sales_data trans1, trans2;
std::cout << "请输入两条相同ISBN的销售记录:" << std::endl;
std::cin >> trans1 >> trans2;
if (compareIsbn(trans1, trans2))
{
std::cout << "汇总信息:ISBN 售出本数 原始价格 实售价格 折扣为:\n" << trans1 + trans2 << std::endl;
}
else {
std::cout << "两条销售记录的ISBN不同" << std::endl;
}
Sales_data total, trans;
std::cout << "请输入几条ISBN相同的销售记录" << std::endl;
if (std::cin >> total) {
while (std::cin >> total)
{
if (compareIsbn(total, trans))//ISBN相同
total = total + trans;
else {
//ISBN不同
std::cout << "当前书籍ISBN不同" << std::endl;
break;
}
}
std::cout << "有效汇总信息: ISBN 售出本数 原始价格 实售价格 折扣为:\n" << total << std::endl;
}
else
{
std::cout << "没有数据" << std::endl;
return -1;
}
int num = 1;//记录当前书籍的销售记录总数
std::cout << "请输入若干销售记录:" << std::endl;
if (std::cin >> trans1)
{
while (std::cin >> trans2)
{
if (compareIsbn(trans1, trans2))//ISBN相同
num++;
else {
//ISBN不同
std::cout << trans1.isbn() << "共有" << num << "条销售记录" << std::endl;
trans1 = trans2;
num = 1;
}
}
std::cout << total.isbn() << "共有" << num << "条销售记录" << std::endl;
}
else {
std::cout << "没有数据" << std::endl;
return -1;
}
return 0;
}
预处理器
- 预处理器是在编译之前执行的一段程序可以部分地改变我们所写的程序
例如预处理器功能#include:预处理器会用指定的头文件内容代替#include,类似于文本替换 - 头文件保护符:是一项依赖于预处理变量的预处理器功能。
预处理变量有两种状态:已定义和未定义
#define
指令把一个名字设定为预处理变量。另外两个指令分别检查某个指定的预处理变量是否已经定义,一旦检查结果为真就会一直执行后续操作直到遇到#endif
终止。如果为假,便会忽略#ifdef
或#ifndef
到#endif
之间的部分
#ifdef
:如果变量已定义则为真
#ifndef
:如果变量未定义则为真 - 预处理器变量可以无视C++语言中关于作用域的规则。
一个名为NULL的预处理变量(preprocsser variable) 米给指针赋值,这个变量在头文件cstdib中定义,它的值就是0。
预处理变量不属于命名空间std.它由预处理器负责管理,因此我们可以直接使用预处理变量而无须在前面加上std::。
用到一个预处理变量时,预处理器会自动地将它替换为实际值,因此用NULL初始化指针和用0初始化指针是一一样的。 在新标准下,现在的C++程序最好使用nullptr,同时尽量避免使用NULL. - 整个程序中的预处理变量包括头文件保护符必须唯一。
通常的做法是基于头文件中类的名字来构建保护符的名字,以确保其唯一性。
为了避免与程序中的其他实体发生名字冲突,一般把预处理变量的名字全部大写。