C++_Primer_5笔记----ch7(上)

1.定义抽象数据类型

类的基本思想就是数据抽象和封装。

struct Scales_data{
	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&);

成员函数
所有成员都必须在类内声明,但成员函数体可以定义在类内也可以定义在类外。

std::string isbn() const { return bookNo; }			//在类内定义

引入this
isbn函数是如何获取bookNo成员所依赖的对象的呢?
通过this 隐式参数

std::string isbn() const { return this->bookNo; }			

引入const
参数列表后和函数体之间加入const,作用就是修饰this指针的。未修饰之前,this的类型是Sales_data* const,修饰之后,this的类型是const Sales_data* const。
const 修改this 的指针类型,this 就成了指向常量的指针,既可以给它赋常量对象的地址,又可以赋非常量对象的地址。
如果this 不是指向常量的指针,就不能绑定到一个常量对象上。
使用const的成员函数称为常量成员函数
常量对象,以及常量对象的引用和指针都只能调用常量成员函数。

在类的外部定义成员函数
名字必须包含它所属的类名

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

函数声明在类内,一旦编译器看到这个函数名,就理解剩余的代码是位于类的作用域内的。所以可以使用units_sold等成员数据。

类相关的非成员函数
一般把这些函数的声明与类放在同一个头文件里,定义放另一个文件里。

构造函数
对象的初始化方式。只要对象被创建,就会执行构造函数。
构造函数不能被声明成const。

struct Scales_data{
	Scales_data() = default;
	Scales_data(const std:: string &s) : bookNo(s) { }
	Scales_data(const std:: string &s, unsigned n, double p) :
				 bookNo(s) , units_sold(n), revenue(p*n) { }
	Scales_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;
}

Scales_data::Scales_data(std::istream &is)		//构造函数
{
	read(is, *this);
}

析构、赋值和拷贝
拷贝:初始化变量,值的方式传递,返回一个对象。
赋值:使用赋值运算符。
析构:销毁对象及所占空间。释放动态内存。

2.访问控制和封装

使用访问说明符加强类的封装性。
public之后的成员可以在整个程序内被访问,public类的成员定义类的接口。
private之后的成员可以被类的成员函数访问。

class Scales_data{
public:
	Scales_data() = default;
	Scales_data(const std:: string &s) : bookNo(s) { }
	Scales_data(const std:: string &s, unsigned n, double p) :
				 bookNo(s) , units_sold(n), revenue(p*n) { }
	Scales_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;
};

class 和struct的唯一区别:默认访问权限不一样。

友元
Scales_data的数据成员是private的,所以read、add、print 函数就不能访问了,类允许友元函数访问类的非公有函数。把一个函数作为友元,则增加一条以friend关键字开头的函数声明即可

class Scales_data{
//友元声明
friend Sales_data add(const Sales_data&, const Sales_data);
friend std::ostream &print(std::ostream&, const Sales_data&);
friend std::istream &read(std::istream&, const Sales_data&);
public:
	Scales_data() = default;
	Scales_data(const std:: string &s) : bookNo(s) { }
	Scales_data(const std:: string &s, unsigned n, double p) :
				 bookNo(s) , units_sold(n), revenue(p*n) { }
	Scales_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&, const Sales_data&);

最好在类开始或结束前集中声明友元。

友元的声明仅仅指定了访问的权限,而非通常意义上的函数声明。
我们还需在外面在声明一次。

3.类的其他特性

类型成员
除了定义数据成员和函数成员外,类还可以定义类型成员。也存在访问限制,可以是public和private中的一种。

class Screen{
public:
	typedef std::string::size_type pos;
private:
	pos cursor = 0;
	pos height = 0, weight = 0;
	std::string contents;
}

用户可以使用pos了,也可以

using pos = std::string::size_type;

可变数据成员
有时希望修改某个数据成员,即使是一个const成员函数内的。加入mutable关键字。

mutable size_t access_ctr;		//数据类型前加上multable

类类型
即使两个类的成员列表完全一致,他们也是不同的类型。

友元再探
除了把非成员函数定义为友元函数,还可以把其他类定义成友元,也可以把其他类的成员函数定义成友元。
友元可以定义在类的内部,这样的函数是隐式内联的。

类之间的友元关系

class Screen{
	friend class Window_mgr;		//Window_mgr是Screen的友元类,Window_mgr可以访问Screen的私有部分
}

如果一个类指定了友元类,则友元类的成员函数可以访问此类包括非公有成员在内的所有成员。
友元关系不存在传递性。每个类负责控制自己的友元类或友元函数。

成员函数作为友元

class Screen{
	//Window_mgr的成员函数clear作为Screen的友元函数
	//Window_mgr::clear必须在Screen类之前被声明
	firend void Window_mgr::clear(ScreenIndex);
}

一个类想把一组重载函数声明为它的友元,则需要对这组函数中的每一个分别声明。

友元声明与作用域
类和非成员函数的声明不是必须在他们的友元声明之前。就算在类的内部定义该函数,也必须在类的外部声明从而使函数可见。

struct X{
	friend void f() {  }	//友元函数定义在类内部
	X() { f(); }			//错误,f 还没声明
	void g();
	void h();
}
void X::g() { return f(); } //错误,f 还没声明
void f();					//声明那个定义在X中的函数
void X::h() { return f(); }//正确,现在f 的声明在作用域中了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值