c++primer 练习题7.47-7.58

7.47--要看用户的需求,如果需要使用到这种隐性的类型转换,则可以这样,但是如果用了explict关键字的话,如果用到这种转换,就要去显示的使用类型转换。所以还是要看用不用得到这种类型转换。
7.48

string null_isbn("99-999-99999-9");//定义了一个值为99-999-99999-9的string变量null_isbn
Sales_date item1(null_isbn);//隐式的类型转换,将string变量null_isbn隐式的转换成Sales_date的对象
Sales_date item2("99-999-99999-9");//错误,不能直接进行两步类型转换,只能一步类型转换
Sales_date item3(string null_isbn("99-999-99999-9"));//正确:一步一步的进行隐式的类型转换

7.49

Sales_date  &combine(Sales_date );
i.combine(s);//可以的,一步隐式转换
Sales_date  &combine(Sales_date& );
i.combine(s);//不可以,Sales_date&指的是Sales_date的地址,无法将string类型的变量转变成Sales_date&地址
Sales_date  &combine(const Sales_date& ) const;
i.combine(s);//不行,combine是要改对象的,const常量对象不能改,不会修改数据成员的函数都要加上const

这里我想普及一个小的知识点,primer前面也讲过了,但是我资质愚钝,现在才明白一些,就是const放在函数声明前面,放在函数声明后面,和放在函数参数前面,有什么区别
1,const放在函数声明前面:放在函数声明最前面就是对返回值类型进行修饰,这里分两种情况,第一种就是按指针传递 那么函数返回值(即指针)的内容不能被修改 例如:

const int * getline();
int *ptr=getline();//错误,getline()的返回值只能被赋给加const修饰的同类型指针
const int * s = getline();//正确,getline()的返回值只能被赋给加const修饰的同类型指针

第二种情况就是按值传递的时候 在函数按值传递时没有什么意义
如果返回值是外部的数据类型,也就是除了基本数据类型之外的类型,比如将函数 xxx Getxxx() 改写为const xxx &Getxxx()能使得程序效率高
2,const放在函数声明后面 这叫const成员函数,例如

int  get_number()  const; // const 成员函数

任何不希望通过本函数修改成员的函数都应该声明为const函数
const成员函数,不能修改数据成员,不能调用其它非const成员函数,否则编译器将报错
例如

class A{
public :
  int  get_number()const;
  void  set_number(int i);
private:
  int number;
};

int A:: get_number()const{
    set_number(6);//错误,调用了非const函数;
    number-=9;//错误,修改了数据成员
}

从思想上去理解,表象就是:const成员函数就是不让修改对象的存储空间,任何当前对象存储空间的修改都会报错
深层次的理解就是 打个比方

class A{
 public :
    void xxx(string);
};

当我们在使用xxx函数的时候,其实用到了两个东西,一个是A*const this,也就是当前的A对象,另一个是string参数
1,不想改变string参数 就用const 修饰它,void xxx(const string ) ;
2,不想改变指向当前对象,就在函数后面加const 得到void xxx(const string ) cosnt;'
--->编译时编译器就会懂了是要编程const A *const this 两个不能变。。。

3,const 修饰函数参数
按值传递时候无所谓
但是按地址传递时候,外部数据类型 xxx get(xxx a)的效率就要比 xxx get(xxx &a)的效率要低,但是反过来讲,xxx get(xxx &a)方法中游客可能对对象数据进行修改,这时候 加上个const就不会出现不小心修改了对象数据地址内存放的地址信息了

7.52
中这样的初始化方式是有问题的,原本的Sales_date类不能这样进行初始化
要写一个7.5.5节这样的聚合类:

class Sales_date{
  std::string bookNo;
  unsigned units_sold;
  double revence;
};

这样再去用

Sales_date item={"ssssssss",12,15.3};

就没有问题了
7.53,
没什么可说的,书上的代码,理解一下costexpr关键字修饰的函数返回的是常量,修饰构造函数时要求函数体为空

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(o){}
    constexpr any(){return hw||io||other;}
    void set_io(bool b){io =b;}
    void set_hw(bool b){hw =b;}
    void set_other(bool b){other =b;}
private:
    bool hw;//硬件错误
    bool io;//io错误
    bool other;//其他错误
};

7.54 根据对constexpr关键字的认识,修饰普通成员函数的时候要返回一个常量
所以不能
7.55
不属于
类不属于字面值类型
7.56
7.56 静态成员就是与类相关独立于类的对象之外的成员。
有些操作使用静态成员十分方便。、
普通成员需要进行类的实例化,是对于对象而言的操作,但是静态数据成员是对于类的操作。
7.57

class Account{
public:
    void calculate(){
        amount += amount * intrestRate;
    }
    static double rate(){
        return intrestRate;
    }
    static void rate(double);
private:
    static constexpr int period = 30;
    double daily_tbl[period];
    std::string owner;
    double amount;
    static double intrestRate;
    static double initRate();
};

7.58
静态的常量表达式要用constexpr修饰

// example.h
class Example {
public:
    static constexpr double rate = 6.5;//加上了constexpr 修饰
    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);//类外初始化vector类型的数据成员

推荐阅读更多精彩内容