c++ primer(第五版)笔记 第七章 类初探

31 篇文章 0 订阅
#ifndef SALES_DATA_H
#define SALES_DATA_H

#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::cerr;
using std::istream;
using std::ostream;
using std::string;

// 类的基本思想:数据抽象(data abstraction)和封装(encapsulation)
	// 数据抽象是依赖于接口(interface)和实现(implementation)分离的编程技术
	// 封装实现了类的接口和实现的分离
	
// const 成员函数:修改隐式 this 指针的类型,const 关键字放在形参列表后面
//常量对象,常量对象的引用或指针都只能调用常量成员函数

//前向声明(forward declaration),向程序引入名字 Sales_data,并指明是一个 class 类型
//从声明开始直到定义之前,Sales_data 是一个未完全类型(incomplete type)
//可以定义指向这种类型的指针或引用,也可以声明(但不能定义)以这种类型为参数或返回类型的函数
class Sales_data;
//class 和 struct 的唯一区别就是默认访问权限的不同
class Sales_data
{
	//友元函数,允许其他类或函数,访问该类的非公有成员
	//友元的声明只是访问权限的设定,并不能代替函数声明
	//定义其他类的友元关系  friend class classname
	//定义其他类成员函数的友元关系  friend classname::function, 必须先声明该函数
	friend ostream &print(ostream &os, const Sales_data &tmp);
	friend istream &read(istream &is, Sales_data &tmp);
//访问说明符,public 之后的成员在整个程序内可以被访问,多用于定义类的接口
public:
	// 构造函数(constructor),只要类的对象被创建,就会执行构造函数
	// 没有返回函数,有一个形参列表和函数体,可以被重载,但不能声明成 const
	// 默认构造函数,无需任何实参,如果没有显式定义构造函数,编译器创建合成默认构造函数
		//初始化数据成员规则:
			//如果存在类内的初始值,用它来初始化成员
			//否则默认初始化该成员
	//默认初始化成员会出现未定义的情况,此时默认构造函数可能执行错误的操作
	//如果含有类类型的成员而且该成员没有默认构造函数,无法执行该成员的初始化
	
	// 通过 s,n,m 构造对象
	Sales_data(string &s, double n, unsigned m):bookNo(s), revenue(n * m), units_sold(m)
	{}
	// = default 要求编译器生成构造函数
	Sales_data() = default;
	// 通过 s 字串构造对象
	//委托构造函数(delegating constractor)
	Sales_data(string &s):Sales_data(s, 0.0, 0){}

	// 通过 is 标准输入流的数据构造对象
	//通过关键字 explicit 抑制隐式类类型转换,只能在类内的构造声明出现,不能出现在类外
	//定义 explicit 后,只能使用直接初始化,不能用拷贝初始化
	explicit Sales_data(istream &is);
	//const 成员函数,获得私有成员变量
	string isbn() const { return bookNo; }
	//普通成员函数,将 tmp 的对象数据,合并到对应成员数据中
	Sales_data &combin(const Sales_data &tmp);
	
//private 访问说明符之后的成员可以被类的成员函数访问,但不能被使用该类的代码访问,隐藏类的实现细节
private:
	// 定义在类内部的函数是隐式的 inline 函数
	double avg_price() const 
	{
		return units_sold ? (revenue / units_sold) : 0;
	}
	//成员的初始化顺序和他们在类中出现的顺序一致
	double revenue = 0.0;
	unsigned units_sold = 0;
	string bookNo;
	//静态成员,存在于任何对象之外,对象中不包含任何与静态成员相关的数据
	//静态成员函数,不包含 this 指针,也不能定义为 const
	//通常使用 域操作符调用 ,也可以同过. ->使用对象调用
	//不通过构造函数初始化,应在类的外部定义并初始化
	//可以是不完全类型,可用静态成员变量作为默认实参
	static double sta_test;
public:
	//可变数据成员,(mutable data member)永远不会是 const
	mutable size_t count = 0;
};

//非成员函数声明
//输出 tmp 对象的信息
ostream &print(ostream &os,const Sales_data &tmp);
//从 is 流中读入数据,用于初始化 tmp 对象 
istream &read(istream &is, Sales_data &tmp);
//接受2个对象,返回一个新的对象,表示他们的和
Sales_data add(const Sales_data &lTmp, const Sales_data &rTmp);
#endif //SALES_DATA_H

#include "Sales_data.h"

Sales_data::Sales_data(istream &is)
{
	read(cin, *this);
}

Sales_data &Sales_data::combin(const Sales_data &tmp)
{
	units_sold += tmp.units_sold;
	revenue += tmp.revenue;
	return *this;
}

ostream &print(ostream &os,const Sales_data &tmp)
{
	os << tmp.bookNo << "(" << tmp.units_sold << ") : "
		<< tmp.revenue << " " << tmp.avg_price();
}

istream &read(istream &is, Sales_data &tmp)
{
	cout << "pls input : bn num price :" << endl;
	is >> tmp.bookNo >> tmp.units_sold >>tmp.revenue;
}

Sales_data add(const Sales_data &lTmp, const Sales_data &rTmp)
{
	Sales_data sum = lTmp;
	sum.combin(rTmp);
	return sum;
}

#include "Sales_data.h"

int main()
{
	//类名直接作为 类型名使用,即使2个类的成员完全一致,也是不同的类型
	//定义对象前,必须完全定义类,因此类不能包含自身类类型的成员
	//类名出现后,就被认为是声明过了,因此可以包含指向自身类型的引用或指针
	Sales_data total;	//等价于 class Sales_data total;
	const Sales_data mutableTest;
	Sales_data test1_total;
	//可变成员变量
	cout << mutableTest.count << endl;
	++mutableTest.count;
	cout << mutableTest.count << endl;
	//隐式类类型转换,仅用于只有一个参数的构造函数,多个参数的不会发生
	string test_book = "99-99-99";
	
	//利用test_book创建了临时对象,该转换的步骤只能有一次
	Sales_data test2_total = test_book;
	//强制类型转换,打破 explicit 限制
	test2_totalcombin(static_cast<Sales_data>(cin));
	//test_total.combin("99-99-99"); 错误,有2步转换,先由 const char [] 转为 string,再有string 转换为类类型
	test1_total.combin(test_book);
	
	if( read( cin, total))
	{
		Sales_data trans;
		while( read( cin, trans))
		{
			if( trans.isbn() == total.isbn())
				total.combin(trans);
			else
			{
				print(cout, total) << endl;
				total = trans;
			}
		}
		print(cout, total);
	}
	else
	{
		cerr << "NO DATA!" << endl;
		return 0;
	}
	return 1;
}
练习
<pre name="code" class="cpp">#ifndef SCREEN_DATA_H
#define SCREEN_DATA_H

#include<string>
#include<iostream>

using std::string;
using std::istream;
using std::ostream;
using std::cout;
using std::cin;
using std::endl;



class Screen
{
friend class Mgr_screen;
// friend void Mgr_screen::clean(Mgr_screen::screensIndex);//单独声明一个友元...这个好难
public:
	typedef string::size_type pos;
//如果一个构造函数为所有形参都提供了默认实参,实际上它也是一个默认构造函数
	Screen() = default;
	Screen(pos a, pos b):
		x(a),y(b),contents(a * b, 'O'){}	
	Screen(pos a, pos b, char c):
		x(a),y(b), contents(a * b, c){}	
		
	char get() const
	{
		return contents[curson];
	}
	char get(pos w, pos h) const
	{
		return contents[h * x + w];
	}
	
	Screen &move(pos, pos);
	Screen &set(char);
	Screen &set(pos, pos, char);
	Screen &display(ostream &os)
	{
		do_display(os);
		return *this;
	}
	const Screen &display(ostream &os) const
	{
		do_display(os);
		return *this;
	}
	
	
private:
	void do_display(ostream &os) const
	{
		os << contents;
	}
	pos x  = 10;
	pos y  = 10;
	pos curson = 0;
	string contents;
};

#endif //SCREEN_DATA_H

#include "screen.h"

Screen &Screen::move(pos w, pos h)
{
	curson = w * x + h;
	return *this;
}

Screen &Screen::set(char c)
{
	contents[curson] = c;
	return *this;
}

Screen &Screen::set(pos w, pos h, char c)
{
	contents[w * x + h] = c;
	return *this;
}

#ifndef MGR_SCREEN_H
#define MGR_SCREEN_H

#include <vector>
#include "screen.h"
using std::vector;

class Mgr_screen
{
public:
	using screensIndex = vector<Screen>::size_type;
	void clean(screensIndex);
	screensIndex addScreen(Screen &s);
private:
	vector<Screen> screens{Screen(25,8,'X')};
};

#endif //MGR_SCREEN_H

#include "mgr_screen.h"

void Mgr_screen::clean(screensIndex i)
{
	Screen &s = screens[i];
	s.contents = string(s.x * s.y, 'M');
}
//返回类型是的作用域位于 Mgr_screen 之外,必须指明作用域
//名字查找(name lookup)寻找与所用名字最匹配的声明
	//1>在名字所在块中寻找,只考虑名字出现之前的声明
	//2>找不到,查找外层作用域
	//3>找不到,报错
	
// 类的定义:
	// 1>先编译成员的声明
	// 2>直到类全部可见才编译函数体
	// 所以成员函数可以使用类中定义的任何名字
Mgr_screen::screensIndex Mgr_screen::addScreen(Screen &s)
{
	screens.push_back(s);
	return screens.size() - 1;
}

#include "screen.h"

int main()
{
	Screen myscreen(5,5,'O');
	myscreen.move(4,0).set('#').display(cout);
	cout << endl;
	myscreen.display(cout);
	cout << endl;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值