C++Primer 学习笔记 第七章 类

本文深入探讨C++的类和对象,包括数据类型的定义、构造函数、拷贝与析构、访问控制(public、private)、封装以及友元函数的概念和应用。讲解了如何通过友元实现非成员函数访问类的private成员,以及类的静态成员和作用。同时,介绍了类的构造函数初始值列表、成员函数的内联和重载,以及聚合类和字面量常量类的特点。
摘要由CSDN通过智能技术生成
//7.1定义数据类型
//7.1.1设计Sales_data类


//7.1.2定义改进的sales_data类
#include "iostream"
#include "string"
using namespace std;
struct Sales_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的非成员函数接口
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream &print(std::ostream&, const Sales_data&);
std::istream &read(std::istream&, Sales_data&);

//引入this
//观察isbn成员函数的调用
//total.isbn();
//在这力我们使用了点运算符来访问total对象的isbn成员,然后调用它。

//引入const成员函数

//类作用域和成员函数

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

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

//7.1.3定义类相关的非成员函数

//类的作者常常需要定义一些辅助函数,比如add、read和print等。
//尽管这些函数定义的操作从概念上来说属于类的接口的组成部分,但它们实际上并不属于类本身
//我们定义非成员函数的方式与定义其他函数一样,通常把函数的声明和定义分离开来。如果函数在概念
//上属于类但是不定义在类中,则它一般应与类声明(而非定义)在同一个头文件内。在这种方式下,用户使用接口的任何部分都只需要引入一个文件。

//定义read和print函数

//定义add函数和print函数与2.6.2节中的代码作用一样,而且代码本身也非常相似

istream &read(istream &is, Sales_data &item) {
	double price = 0;
	is >> item.bookNo >> item.units_sold >> price;
	item.revenue = price*item.units_sold;
	return is;
}

ostream &print(ostream &os, const Sales_data &item) {
	os << item.isbn() << " " << item.units_sold << " "
		<< item.revenue << " " << item.avg_price();
	return os;
}

//定义add函数
//add函数接受两个sale_data对象作为其参数,返回值是一个新的sales_data,用于表示前两个对象的和:
Sales_data add(const Sales_data &lhs, const Sales_data &rhs) {
	Sales_data sum = lhs;
	sum.combine(rhs);      //把rhs的数据成员加到sum当中。
	return sum;
}


//7.1.4构造函数
//合成的默认构造函数

//某些类不能依赖于合成的默认构造函数

//构造函数初始值列表

//在类的外部定义构造函数

//7.1.5拷贝、赋值和析构
//某些类不能依赖于合成的版本


//7.2访问控制与封装

//定义在public说明符之后的成员在整个程序内可悲访问,public成员定义类的接口
//定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问
//private部分封装了类的实现细节。

//使用class和struct关键字
//唯一区别是默认的访问权限。

//7.2.1 友元
//既然,sales_data的数据成员是private的,我们的read、print和add函数也就无法正常编译了,
//这是因为尽管这几个函数是类的接口的一部分,但他们不是类的成员
//类可以允许其他类或者函数访问它的非公有成员,方法是零其他类或者函数成为它的友元。如果想把一个函数作为
//它的友元,只需要增加一条以关键字friend开始的函数声明语句即可。
//友元声明只能出现在类定义的内部,但是在类内出现的具体位置不限。友元不是类的成员也不受它所在区域访问控制级别的约束。



//7.3类的其他特性

//7.3.1类成员再探

//定义一个类型成员

//class Screen
//{
//public:
//	typedef std::string::size_type pos;
//
//
//private:
//	pos cursor = 0;//光标位置
//	pos height = 0, width = 0;//屏幕尺寸
//	std::string contents;
//};

//Screen类的成员函数
//要使我们的类更加实用,还需要添加一个构造函数令用户能够定义屏幕的尺寸和内容,以及其他两个成员
//分别负责移动光标和读取给定位置的字符:

class Screen
{
public:
	typedef std::string::size_type pos;
	Screen() = default;
	Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht*wd, c) {};
	char get() const { return contents[cursor]; };//读取光标处的字符,隐式内联
	inline char get(pos ht, pos wd) const;//显式内联
	Screen &move(pos r, pos c);//能在之后被设置位内联
private:
	pos cursor = 0;//光标位置
	pos height = 0, width = 0;//屏幕尺寸
	std::string contents;

};

//令成员作为内联函数
//在类中,常有一些规模较小的函数适合于被声明成内联函数。如我们之前所见的,定义在类内部的成员函数
//是自动inline的。因此screen的构造函数和返回光标所指字符的get函数默认是inline的
//我们可以在类的内部把inline作为声明的一部分显式地声明成员函数,同样,也可以在类的外部用inline关键字修饰函数的定义:

inline Screen&Screen::move(pos r, pos c) {
	pos row = r*width;
	cursor = row + c;
	return *this;
}

char Screen::get(pos r, pos c) const {
	pos row = r*width;
	return contents[row + c];
}

//虽然我们无须再声明和定义的地方同时说明inline,但这么做其实是合法的。不过,
//最好再类外部定义的地方说明inline,这样可以使类更容易理解。


//重载成员函数
//和非成员函数一样,成员函数也可以被重载(参见6.4节,第206页),只要函数之间再参数的数量和/或类型上有所区别就行。

//可变数据成员
//有时,会发生这样一种情况,我们希望能修改类地某个数据成员,即使是在一个const成员函数内。可以通过在变量的声明中假如mutale关键字做到这一代你。
//一个可变的数据成员永远不会是const,即使它是const对象的成员。



//7.3.2返回*this的成员函数


//7.3.3类类型

//7.3.4友元再探
//类还可以把其他的类定义成友元,也可以把其他类的成员函数定义成友元。此外,友元函数能定义在类的内部,这样的函数使隐式内联的。



//7.4类的作用域

//7.4.1名字查找与类的作用域


//7.5构造函数再探

//7.5.1构造函数的初始值列表

//构造函数的初始值有时必不可少

//成员初始化的顺序

//7.5.2委托构造函数

//7.5.3默认构造函数的作用

//7.5.4隐式的类类型转换

//7.5.5聚合类
//聚合类使得用户可以直接访问其成员,并且具有特殊的初始化语法形式。
//1.所有成员都是public的
//2.没有定义任何构造函数
//3.没有类初始值
//4.没有基类,也没有virtual函数
//如下:
struct data
{
	int ival;
	string s;
};

//7.5.6字面值常量类
 
//7.6类的静态成员
//有的时候需要他的一些成员与类本身直接相关,而不是与类的各个对象保持关联。
//例如:一个银行账户类可能需要一个数据成员来表示当前的基准利率。在此例中,我们希望利率与类关联,
//而非与类的每个对象关联。从实际效率来看,没有必要每个对象都存储利率信息。而且更加重要的是,一旦利率变动
//我们希望所有的对象都使用新值。


//声明静态成员
//我们通过在成员的声明之前加上关键字static使得其与类关联在一起。和其他成员一样,
//静态成员可以是public的或private的。静态数据成员的类型可以使常量、引用、指针、类类型等。

//example:
class Account
{
public:
	void calcuatr() { amount += amount*interestRate; }
	static double rate() {
		return interestRate;
	};
	static void rate(double);

private:
	std::string owner;
	double amount;
	static double interestRate;
	static double initRate();
};

//注:静态成员函数也不与任何对象绑定在一起,他们不包含this指针。作为结果,静态成员函数不能声明成const的,而且我们也不能再static函数体
//内使用this指针。这一限制既适用于this的显式使用,也对调用非静态成员的隐式使用有效。

//使用类的静态成员
double r = Account::rate();

//定义静态成员

//静态成员的类内初始化

//静态成员能用于某些场景,而普通成员不能

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值