C++Primer_课后习题第七章

本文答案,部分参考于C++ Primer 习题集

前面章节的习题答案

第一章

第二章

第三章

第四章

第五章

第六章

7.1

在这里插入图片描述

在这里插入图片描述

7.2

class Sales_data{
private:            //定义私有数据成员
    string bookNo;  //书籍编号,隐式初始化为空串
    unsigned units_sold=0;      //销售量,显式初始化为0
    double sellingprice=0.0;    //原始价格,显式初始化为0
    double saleprice=0.0;       //实售价格,显式初始化为0.0
    double discount=0.0;        //折扣.显式初始化为0.0
public:             //定义共有数据成员
    //isbn函数只有一条语句,返回bookNo
    string isbn() const {return bookNo;};
    //combine函数用于把两个ISBN相同的销售记录合并在一起.
    Sales_data & combine(const Sales_data &rhs){
        units_sold += rhs.units_sold;       //累加书籍的销售量.
        saleprice =(rhs.saleprice*rhs.units_sold+saleprice*units_sold)/(rhs.units_sold+units_sold);     //重新计算实际销售价格
        if(saleprice!=0)
            discount=saleprice/sellingprice;                                                            //重新计算实际折扣
        return *this;                                                                                   //返回合并后的结果
    }
}

7.3

#include <iostream>
#include <istream>
#include <string>
#include "Sale_data.h"
using namespace std;
Sale_data add(const Sale_data &lhs,const Sale_data &rhs){
    Sale_data sum=lhs;
    sum.combine(rhs);
    return sum;
}
std::istream &read(std::istream &is,Sale_data &item){
    is>>item.bookNo>>item.units_sold>>item.sellingprice>>item.saleprice;
    return ls;
}
std::ostream &print(std::ostream &os,const Sale_data &item){
    os<<item.isbn()<<""<<item.units_sold<<""<<item.sellingprice<<""<<item.saleprice<<" "<<item.discount;
    return os;
}
int main() {
    cout<<"请输入交易记录(ISBN,销售量,原价,实际售价):"<<endl;   
    Sale_data total;                                        //保存下一条交易记录
    //读入第一条交易记录,并确保有数据可以处理
    if(cin>>total){
        Sale_data trans;            //保存和的变量
        //读入并处理剩余交易记录
        while(cin>>trans){
            //如果我们仍在处理相同的书
            if(total.isbn()==trans.isbn())
                trans=add(trans,total);
            else{
                //打印前一本书的结果
                cout<<total<<endl;
                total=trans;        //total现在表示下一本书销售额
            }
        }
        //打印最后一本书的结果
        cout<<total<<endl;
    }
    else{
        //没有输入!警告读者
        cerr<<"No data!?"<<endl;
        return -1;
    }
    return 0;
}

除了读入和输出不一样之外,其他的都是一样的.

7.4

class Person{
    string name="";
    string address="";
}

7.5

class Person{
    string name="";
    string address="";
    string get_name() const  {return name;};
    string get_address() const {return address};
}

应该是const 类的.因为姓名和地址一般都是不可以改变的变量.

7.6

Sale_data add(const Sale_data &lhs,const Sale_data &rhs){
    Sale_data sum=lhs;
    sum.combine(rhs);
    return sum;
}
std::istream &read(std::istream &is,Sale_data &item){
    is>>item.bookNo>>item.units_sold>>item.sellingprice>>item.saleprice;
    return ls;
}
std::ostream &print(std::ostream &os,const Sale_data &item){
    os<<item.isbn()<<""<<item.units_sold<<""<<item.sellingprice<<""<<item.saleprice<<" "<<item.discount;
    return os;
}

7.7

#include <iostream>
#include <istream>
#include <string>
using namespace std;
Sale_data add(const Sale_data &lhs,const Sale_data &rhs){
    Sale_data sum=lhs;
    sum.combine(rhs);
    return sum;
}
std::istream &read(std::istream &is,Sale_data &item){
    is>>item.bookNo>>item.units_sold>>item.sellingprice>>item.saleprice;
    return ls;
}
std::ostream &print(std::ostream &os,const Sale_data &item){
    os<<item.isbn()<<""<<item.units_sold<<""<<item.sellingprice<<""<<item.saleprice<<" "<<item.discount;
    return os;
}
int main() {
    cout<<"请输入交易记录(ISBN,销售量,原价,实际售价):"<<endl;   
    Sale_data total;                                        //保存下一条交易记录
    //读入第一条交易记录,并确保有数据可以处理
    if(read(total)){
        Sale_data trans;            //保存和的变量
        //读入并处理剩余交易记录
        while(cin>>trans){
            //如果我们仍在处理相同的书
            if(total.isbn()==trans.isbn())
                trans=add(trans,total);
            else{
                //打印前一本书的结果
                print(total);
                total=trans;        //total现在表示下一本书销售额
            }
        }
        //打印最后一本书的结果
        print(total);
    }
    else{
        //没有输入!警告读者
        cerr<<"No data!?"<<endl;
        return -1;
    }
    return 0;
}

7.8

read 我们是需要改变给定的Sales_data的值的

但是print只需要输出即可,并不需要改变值.

7.9

std::istream &read(std::istream &is,Person &item){
    is>>item.name>>item.address;
    return ls;
}
std::ostream &print(std::ostream &os,const Person &item){
    os<<item.name<<item.address;
    return os;
}

7.10

因为read函数的返回类型是引用,所以read(cin,data1)的返回值可以继续作为外层的read函数的实参使用,该条件检验读入data1和data2的过程是否正确,如果正确,条件满足,否则条件不满足.

7.11

#include <iostream>
#include <istream>
#include <string>
#include "Sale_data.h"
using namespace std;
// Sale_data add(const Sale_data &lhs,const Sale_data &rhs){
//     Sale_data sum=lhs;
//     sum.combine(rhs);
//     return sum;
// }
// std::istream &read(std::istream &is,Person &item){
//     is>>item.name>>item.address;
//     return ls;
// }
// std::ostream &print(std::ostream &os,const Person &item){
//     os<<item.name<<item.address;
//     return os;
// }

class Sales_data{
private:            //定义私有数据成员
    string bookNo;  //书籍编号,隐式初始化为空串
    unsigned units_sold=0;      //销售量,显式初始化为0
    double sellingprice=0.0;    //原始价格,显式初始化为0
    double saleprice=0.0;       //实售价格,显式初始化为0.0
    double discount=0.0;        //折扣.显式初始化为0.0
    Sales_data()=default;       //默认初始化
    Sales_data(const string &book) : bookNo(book){} //参数是一个string,然后把这个string给bookNo赋值
    Sales_data(const string &book,const unsigned num,const double sellp,const double salep);
    Sales_data(istream &is); 
public:             //定义共有数据成员
    //isbn函数只有一条语句,返回bookNo
    string isbn() const {return bookNo;};
    //combine函数用于把两个ISBN相同的销售记录合并在一起.
    Sales_data & combine(const Sales_data &rhs){
        units_sold += rhs.units_sold;       //累加书籍的销售量.
        saleprice =(rhs.saleprice*rhs.units_sold+saleprice*units_sold)/(rhs.units_sold+units_sold);     //重新计算实际销售价格
        if(saleprice!=0)
            discount=saleprice/sellingprice;                                                            //重新计算实际折扣
        return *this;                                                                                   //返回合并后的结果
    }
}
Sales_data(const string &book,const unsigned num,const double sellp,const double salep){
    bookNo=book;
    units_sold=num;
    sellingprice=sellp;
    saleprice=salep;
    if(sellingprice!=0)
        discount=saleprice/sellingprice;    //计算实际折扣
}
Sales_data(istream &is){
    is>>*this;
}

// class Person{
//     string name="";
//     string address="";
//     string get_name() const  {return name;};
//     string get_address() const {return address};
// }
int main() {
    Sales_data data1;
    Sales_data data2("978-7-121-15535-2");
    Sales_data data3("978-7-121-15535-2",100,128,109);
    Sales_data data4(cin);
    cout<<"书籍的销售情况是:"<<endl;
    cout<<data1<<"\n"<<data2<<"\n"<<data3<<"\n"<<data4<<"\n";
    return 0;
}

7.12

class Sales_data{
private:            //定义私有数据成员
    string bookNo;  //书籍编号,隐式初始化为空串
    unsigned units_sold=0;      //销售量,显式初始化为0
    double sellingprice=0.0;    //原始价格,显式初始化为0
    double saleprice=0.0;       //实售价格,显式初始化为0.0
    double discount=0.0;        //折扣.显式初始化为0.0
    Sales_data()=default;       //默认初始化
    Sales_data(const string &book) : bookNo(book){} //参数是一个string,然后把这个string给bookNo赋值
    Sales_data(const string &book,const unsigned num,const double sellp,const double salep);
    Sales_data(istream &is){is>>*this;}
public:             //定义共有数据成员
    //isbn函数只有一条语句,返回bookNo
    string isbn() const {return bookNo;};
    //combine函数用于把两个ISBN相同的销售记录合并在一起.
    Sales_data & combine(const Sales_data &rhs){
        units_sold += rhs.units_sold;       //累加书籍的销售量.
        saleprice =(rhs.saleprice*rhs.units_sold+saleprice*units_sold)/(rhs.units_sold+units_sold);     //重新计算实际销售价格
        if(saleprice!=0)
            discount=saleprice/sellingprice;                                                            //重新计算实际折扣
        return *this;                                                                                   //返回合并后的结果
    }
}

7.13

int main() {
    Sale_data total(cin);                                        //保存下一条交易记录
    //读入第一条交易记录,并确保有数据可以处理
    if(cin){
        Sale_data trans(cin);            //保存和的变量
        //读入并处理剩余交易记录
        do{
            //如果我们仍在处理相同的书
            if(total.isbn()==trans.isbn())
                trans=add(trans);
            else{
                //打印前一本书的结果
                print(total);
                total=trans;        //total现在表示下一本书销售额
            }
        }while(read(cin,trans));
        //打印最后一本书的结果
        print(total);
    }
    else{
        //没有输入!警告读者
        cerr<<"No data!?"<<endl;
        return -1;
    }
    return 0;
}

7.14

Sale_data(const string &book):bookNo(book),units_sold(0),sellingprice(0),saleprice(0),discount(0){}

7.15

class Person{
private:
    string name="";
    string address="";
public:
    Person()=default;
    Person(const string &name,const string &add){
        name=name;
        address=add;
    }
    Person(istream &is){is>>*this}
public:
    string get_name() const  {return name;};
    string get_address() const {return address};
};

7.16

① 没有,

一般来讲

构造函数和一部分成员函数应该定义在public说明符之后

数据成员合作为实现部分的函数则应该跟在private说明符之后

7.17

class和struct都可以用来声明类,它们的大多数功能都类似,唯一的区别是默认访问权限不同.

class 第一个定义的访问说明符的成员是private

struct 第一个定义的访问说明符的成员是public

7.18

封装是指保护类的成员不被随意访问的能力,通过把类的实现细节设置为private

我们就能完成对类的封装,封装实现了接口和实现的分离

如书中所述.

封装有两个重要的优点,一是确保用户代码不会无意间破坏封装对象的状态;二是被封装的类的具体实现细节可以随时改变.而无须调整用户级别的代码。

一旦吧数据定义成为private的,类的作者就可以比较自由的修改数据了.当实现部分发生改变时,只需有检查类的代码本省及确定这次改变有什么影响.

换句话说,只要类的接口不变.用户代码就无须改变.如果数据是public的,则所有使用了原来数据成员的代码都可能失效,这时我们必须定位并重新写所有依赖于老版本实现的代码,之后才能重新使用该程序.

把数据成员的访问权限设为private还有另外的一个好处,这么做能防止由于用户的原因造成数据被破化,如果我们发现有程序缺陷破坏了对象的状态 ,则可以在有限的范围内定位缺陷,因为只有实现部分的代码可能产生这样的错误,因此,个错误的搜索限制在有限范围内将能极大的简化更改问题及修正程序等工作.

7.19

我们需要把姓名和地址变成private

然后构造函数和接口函数设置为public

7.20

当非成员函数确实需要访问类的私有成员时,我们可以把他声明为该类的友元,

这时,友元可以 “工作在类的内部”,像类的成员一样访问类的所有数据和函数,但是一旦使用不慎(比如随意设定友元)就有可能破坏类的封装性

7.21

class Sales_data{
    friend Sales_data add(const Sales_data &lhs,const Sales_data &rhs);
    friend Sales_data istream &read(istream &is,const Sales_data &item);
    friend Sales_data ostream &print(ostream &os,const Sales_data &item);
private:            //定义私有数据成员
    string bookNo;  //书籍编号,隐式初始化为空串
    unsigned units_sold=0;      //销售量,显式初始化为0
    double sellingprice=0.0;    //原始价格,显式初始化为0
    double saleprice=0.0;       //实售价格,显式初始化为0.0
    double discount=0.0;        //折扣.显式初始化为0.0
}

7.22

class Person{
private:
    string name;
    string address;
public:
    Person()=default;
    Person(const string &name,const string &add){
        name=name;
        address=add;
    }
    Person(istream &is){is>>*this}
public:
    string get_name() const  {return name;};
    string get_address() const {return address};
};

7.23

class Screen{
private:
    unsigned height=0,width=0;
    unsigned currsor=0;
    string contents;
}

7.24

class Screen{
    Screen() = default;          //这个就是默认的构造函数
    Screen(const unsigned h,const unsigned w) : height(h),width(w),contents(ht*wd,' ') {};
    Screen(const unsigned h,const unsigned w,const char c):  height(h),width(w),contents(ht*wd,C){};
private:
    unsigned height=0,width=0;
    unsigned currsor=0;
    string contents;            //屏幕的内容
}

7.25

Screen的4个数据成员都是内置类型 (String类定义了拷贝和赋值运算符) ,因此直接使用类对象执行拷贝和赋值操作是可以的.

7.26

这题是参考的答案.

隐式的内联

class Sales_data{
public:
    double avg_price() const{
        if(units_sold)
            return revenue/units_sold;
        else
            return 0;
    }
}

显示的内联

class Sales_data{
    double avg_price() const;
}
inline double Sales_data :: avg_price() const{
    if(units_sold)
            return revenue/units_sold;
        else
            return 0;
}

7.27

#include<iostream>
#include<string>
using namespace std;

class Screen {
public:
    Screen() = default;          //这个就是默认的构造函数
    Screen(const unsigned h, const unsigned w) : height(h), width(w), contents(h* w, ' ') {};
    Screen(const unsigned h, const unsigned w, const char c) : height(h), width(w), contents(h* w, c) {};
private:
    unsigned height = 0, width = 0;
    unsigned currsor = 0;
    string contents;            //屏幕的内容
public:
    Screen& move(unsigned r, unsigned c) {
        currsor = r * width + c;
        return *this;
    }
    Screen& set(char ch) {
        contents[currsor] = ch;
        return *this;
    }
    Screen& set(unsigned r, unsigned c, char ch) {
        contents[r * width + c] = ch;
        return *this;
    }
    Screen& display() {
        cout << contents;
        return *this;
    }
};
int main(void) {
    Screen myScreen(5, 5, 'X');
    myScreen.move(4, 0).set('#').display();
    cout << "\n";
    myScreen.display();
    cout << "\n";
    return 0;
}

结果如下:

XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXX#XXXX

7.28+7.29

move set display 都不会改变myScreen的值.改变的都只是一个临时的变量.

#include<iostream>
#include<string>
using namespace std;

class Screen {
public:
    Screen() = default;          //这个就是默认的构造函数
    Screen(const unsigned h, const unsigned w) : height(h), width(w), contents(h* w, ' ') {};
    Screen(const unsigned h, const unsigned w, const char c) : height(h), width(w), contents(h* w, c) {};
private:
    unsigned height = 0, width = 0;
    unsigned currsor = 0;
    string contents;            //屏幕的内容
public:
    Screen move(unsigned r, unsigned c) {
        currsor = r * width + c;
        return *this;
    }
    Screen set(char ch) {
        contents[currsor] = ch;
        return *this;
    }
    Screen set(unsigned r, unsigned c, char ch) {
        contents[r * width + c] = ch;
        return *this;
    }
    Screen& display() {
        cout << contents;
        return *this;
    }
};
int main(void) {
    Screen myScreen(5, 5, 'X');
    myScreen.move(4, 0).set('#').display();
    cout << "\n";
    myScreen.display();
    cout << "\n";
    return 0;
}

结果如下:

XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXXXXXXX

7.30

通过this指针访问成员的优点是,可以非常明确的指出访问的是对象的成员.并且可以在成员函数中使用与数据成员同名的形参,缺点是显得多余,代码不够简洁.

7.31

class X;                                    //声明类型X
class Y{                                    //定义类型Y
    X* x;
};
class X{                                    //定义类型Y
    Y y;
};  

7.32

#include<iostream>
#include<string>
using namespace std;
class Window_mgr{
public:
    void clear();
};
class Screen{
    friend void Window_mgr:: clear();
private:
    unsigned height=0,width=0;
    unsigned cursor=0;
    string contents;
public:
    Screen()=default;       //默认构造函数
    Screen(unsigned ht,unsigned wd,char c):height(ht),width(wd),contents(ht*wd,c){}
};
void Window_mgr::clear(){
    Screen myScreen(10,20,'X');
    cout<<"清理之前myScreen的内容是:"<<endl;
    cout<<myScreen.contents<<endl;
    myScreen.contents="";
    cout<<"清理之后myScreen的内容是:"<<endl;
    cout<<myScreen.contents<<endl;
}
int main(void){
    Window_mgr w;
    w.clear();
    return 0;
}

7.33

Screen :: pos Screen ::size() const{
    return height*width;
}

7.34

会导致编译出错,因为对pos的使用出现在它的声明之前.此时编译器并不知道pos到底是什么含义.

7.35

typedef string Type;        //string类型
Type initVal();             //string类型
class Exercise{
public:
    typedef double Type;    //double类型
    Type setVal(Type);      //double类型
    Type initVal();         //double类型
private:
    int val;
};
//double类型
Type Exercise :: setVal(Type parm){     
    val=parm+initVal();
    return val;
}

会报错.

修改后的代码如下:

typedef string Type;        //string类型
Type initVal();             //string类型
class Exercise{
public:
    typedef double Type;    //double类型
    Type setVal(Type);      //double类型
    Type initVal();         //double类型
private:
    int val;
};
//double类型
Exercise::Type Exercise :: setVal(Type parm){     
    val=parm+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

① cin的那个使用的是 std::istream & 参数的构造函数,该对象的成员值依赖于用户的输入.

② 用的是默认的构造函数

③ 用的是 const string & 参数的构造函数.bookNo使用实参初始化为"9-999-99999-9"

其他的初始化为0

7.38

Sales_data(std::istream &is=std::cin){is>>&this;}

这时候,

Sales_data()=default;

应该去掉,否则会引起二义性

7.39

会引起二义性的错误.

7.40

这题也是参考的.

下面是答案

class 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;}
};

Tree的

class Tree{
private:
    string Name;
    unsigned Age=0;
    double Height=0;
public:
    Tree()=default;
    Tree(const string &n,unsigned a,double h):Name(n),Age(a),Height(h);
}

7.41

#include<iostream>
#include<string>
using std::string;
using std::cin;
using std::cout;
using std::endl;
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 << "该构造函数无须接受任何信息";
    }
    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; //销售量
    double sellingprice = 0.0;    //原始价格
    double saleprice = 0.0;   //实售价格
    double discount = 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;
    return os;
}
int main(void) {
    Sales_data fist("978-7-121-15535-2", 85, 128, 109);
    Sales_data second;
    Sales_data third("978-7-121-15535-2");
    Sales_data last(cin);
    return 0;
}

结果如下:

该构造函数接受书号,销售量,实际售价四个信息
该构造函数接受书号,销售量,实际售价四个信息
该构造函数无须接受任何信息该构造函数接受书号,销售量,实际售价四个信息
该构造函数接受书号信息
该构造函数接受书号,销售量,实际售价四个信息
该构造函数无须接受任何信息
a 10 100 85
该构造函数接受用户输入的信息

程序先执行受委托构造函数,然后才执行构造函数本身的语句.

7.42

class 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){}
    Book():Book("","",0,"",""){}
    Book(std::istream &is):Book(){is>>*this;}
};

7.43

#include<iostream>
#include<string>
using namespace std;
class NoDefault{
public:
    NoDefault(int i){
        val=i;
    }
    int val;
};
class C{
public:
    NoDefault nd;
    //必须显示调用Nodefault的带参构造函数初始化nd
    C(int i=0):nd(i){}
};
int main(void){
    C c;    //使用了类型C的构造函数
    cout<<c.nd.val<<endl;
    return 0;
}

7.44

不合法,因为NoDefault没有默认的构造函数

7.45

合法的,因为我们给类型C添加了默认的构造函数

7.46

(a) 是错误的,类可以不提供任何构造函数,这时,编译器自动实现一个合成的默认构造函数.

(b) 是错误的,如果某个构造函数包含若个形参,但是同时为这些形参都提供了默认实参,则该构造函数也具备默认构造函数的功能.

© 是错误的,因为如果一个类没有默认构造函数,也就是说我们定义了该类的某些构造函数但是没有为其设计默认的构造函数,则当编译器确实需要隐式地使用默认构造函数时,该类无法使用,所以一般情况下,都应该为该类构建一个默认构造函数.

(d) 是错误的,对于编译器合成的默认构造函数来说,类类型的成员执行各自所属类的默认构造函数,内置类型和复合类型的成员值只对定义在全局作用于的对象执行初始化.

7.47

接受一个string参数的Sales_data构造函数应该是explicit的,否则,编译器就有可能自动把一个string对象转换成Sales_data对象,这种做法显得有些随意,某些时候与程序员的初衷相违背

使用explicit的优点是:

避免因隐式类类型转换而带来的意想不到的错误,缺点是当用户需要这样的类类型转换时,不得不使用稍微繁琐的方式来实现.

7.48

在本题给出的代码中,第一行创建了一个string对象,第二行和第三行都是调用Sales_data的构造函数(该构造函数接受一个string)创建它的对象.

此处无须任何类型转换.所以无论Sales_data的构造函数是不是explicit的,item1和item2都能被正确地创建.它们的bookNo成员都是9-999-99999-9,其他成员都是0

7.49

(a)是正确的,编译器首先用给定的string对象自动创建一个Sales_data对象,然后这个新生成的临时对象传给combine的形参(类型是Sales_data),函数正确执行并返回结果

(b) 无法编译通过,因为combine函数的参数是一个非常量引用,而s是一个string对象,编译器用s自动创建一个Sales_data临时对象,但是这个新生成的临时对象无法传递给combine所需的非常亮引用,如果我们吧函数声明修改为Sales_data &combine(constant Sales_data) ;

就可以了.

7.50

我们之前定义的Person含有三个构造函数,因为前两个构造函数接受的参数个数都不是1,所以它们不存在隐式转换的问题,当然也不必指定explicit

Person类的最后一个构造函数

Person(std::istream &is) ; 只接受一个参数,默认情况下,它会把读入的数据自动转换成Person对象.我们更倾向于严格控制Person对象的生成过程,如果确实需要使用Person对象.可以明确的指定.

在其他情况下则不希望自动类型转换的发生,所以应该吧这个构造函数指定为explicit的.

7.51

string 接受的单参数是const char *类型,如果我们得到了一个常量字符串指针.(字符数组) ,

则把它看作string对象是自然而然的过程,编译器自动把参数类型转换成类类型也非常复合逻辑,因此我们无须指定为explicit的

与string相反,vecotr接受的单参数是int类型,这个参数的原意是指定vector的容量,如果我们在本来需要vector的地方提供一个int值,并且希望这个int值,自动转换成vector,则这个过程显得比较牵强.因此把vector的单参数构造函数定义成explicit更加合理.

7.52

这种初始化方式是聚合类的初始化方式.

而我们的Sales_data不是聚合类.

要使用这种初始化的方式的话.我们需要把Sales_data变成聚合类.

下面是代码

struct Sales_data
{
    string bookNo;
    unsigned units_sold;
    double revenue;
};

7.53

就是讲,用书上的那个

7.54

不能

这些以constexpr函数只能包含return 语句,不允许执行其他任务.

7.55

因为Data是聚合类,所以它也是一个字面值常量类.

7.56

静态成员是指声明之前带有关键字static的类成员,静态成员不是任意单独对象的组成部分,而是由该类的全体对象所共享.

静态成员的优点包括:作用域位于类的范围之内,避免与其他类的成员或者全局作用域的名字冲突;可以是私有成员,而全局变量不可以;通过阅读程序可以非常容易看出静态成员与特定类关联,使得程序的含义清晰明了.

静态成员与普通成员的区别主要体现在普通成员与类的对象关联,是某个具体对象的组成部分;而静态成员不从属于任何具体的对象,它由该类的所有对象共享.

另外,还有一个细微的区别,静态成员可以作为默认实参,而普通数据成员不能作为默认实参.

7.57

class Account{
private:
    string strName;
    double dAmount=0.0;
    static double dRate;
}

7.58

rate 和vec的初始化是错误的.

example.c 我们必须给出静态成员的初始指.

导图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Huangpengyu123/article/details/107496766