C++Primer_Chap07_类_List01_定义抽象数据类型

struct Sales_data
{
	//std::string Sales_data::isbn( const Sales_data * const this){return this->isbn;}
	std::string isbn() const {return bookNo;}
	Sales_data& combine( const Sales_data& );
	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, const Sales_data );

const成员函数:紧随参数列表之后的const关键字的作用是将this声明成指向常量的指针。默认情况下,this的类型是指向类类型非常量版本的常量指针,所以不能把this绑定到一个常量对象上(因为this是顶层const而不是底层const)。这也就使得不能在一个常量对象上调用普通的成员函数,为了能够是不需要改变this所指对象的成员函数中,把this设置成指向常量的指针有助于提高函数的灵活性。即const类对象只能调用该类内的const成员函数。

类作用域和成员函数

    类本身是一个作用域,类的成员函数的定义嵌套在类的作用域之内。由于编译器分两步处理类:首先编译成员的声明,然后才编译成员函数体。所以,成员函数体可以随意使用类中的其他成员而无须在意这些成员出现的次序。

在类的外部定义成员函数:

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

定义一个返回this对象的函数

Sales_data& combine( const Sales_data& rhs)
{
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}

    一般来说,定义的函数类似于某种内置运算符时,应该令该函数的行为尽量模仿这个运算符。内置的赋值运算符把它的左侧运算对象当做左值返回,因此为了保持一致,combine函数返回引用类型。

定义类相关的非成员函数

    类的作者常常需要定义一些辅助函数。尽管这些函数的定义的操作从概念上来说属于类的接口的组成,但实际上不属于类本身。这种函数一般应与类声明(而非定义)在同一个头文件。

std::istream& read( std::istream &is, const 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)
{
	os << item.isbn() << " " << item.units_sold << " "
		<< item.revenue << " " << item.avg_price();
	return os;
}

    1.接受的IO类型的引用作为参数是因为IO类属于不能拷贝的类型,只能通过引用传递。同时由于会改变流的内容,所以是破铜引用,而非对常量的引用。

    2.一般来说,执行输出任务的函数应该尽量减少对格式的控制,将是否需要换行有用户代码来决定。

Sales_data add( const Sales_data& lhs, const Sales_data & rhs)
{
	Sales_data sum = lhs;
	sum.combine(rhs);
	return sum;
}

构造函数

    构造函数的名字和类名相同,没有返回类型,且不能被声明成const,可以被重载。某些类不能依赖合成的默认构造函数,必须定义自己的默认构造函数(有且只有在类没有声明任何构造函数时,编译器才会自动生成默认的构造函数。,原因有三:

  1. 如果一个类在某种情况下需要控制对象初始化,那么该类可能在所有情况下都需要控制。
  2. 某些类的编译器生成的默认构造函数可能执行错误的操作。(类成员有复合类型(数组、指针))
  3. 如果类中包含一个其他类类型的成员且这个成员的类型没有默认构造函数,那么编译器将无法初始化该成员。
struct Sales_data
{
	//
	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& );
	double avg_price() const;
	//
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
}

    在C++11新标准中,如果我们需要默认的行为,那么可通过在参数列表后面=default来要求编译器生成构造函数。其中+default可以和声明一起出现在类的内部(此时,默认构造函数内联),也可以作为定义出现在类的外部(默认不是内联)。

    冒号和冒号与花括号之间的代码是构造函数初始化列表。

猜你喜欢

转载自blog.csdn.net/accumulating_mocai/article/details/80904411