第3章 class
3.1 C语言–面向过程
- 定义:定义结构体、对结构体的操作函数
 
- 使用:传入结构体指针、对应的参数
 
 typedef struct point {       float x; 	float y; }Point; void print(const Point *p){     printf("%f %f\n",p->x,p->y); } void move(Point* p,int dx,int dy){     p->x += dx; p->y += dy; }
  Point a; a.x = 1;a.y = 2; move(&a,2,2); print(&a);
 
  | 
 
3.2 C++语言–面向对象
- 定义:将对象和操作绑定到一起
 
- 使用:操作Point对象
 
 class Point{ public:     void init(int x,int y);     void move(int dx,int dy);     void print()const;      private:     int x;     int y; }
  void Point::init(int ix,int iy){ 	x = ix; y = iy; } void Point::move(int dx,int dy){     x += dx; y += dy; } void Point::print() const{     cout << x << ' ' << y << endl; }
  Point a; a.init(1,2); a.move(2,2); a.print();
 
  | 
 
3.3 :: resolver
< Class Name >::< function name >
::< function name >
void S::f(){ 	::f();     ::a++;     a--; }
  | 
 
3.4 Container容器
container:是一个能够保存其它对象的object
stash:是一个可以存储变量、运行时可以扩展的container
要求:
- 无类型限制
 
- 存储的对象类型相同
 
- 操作:add()、fetch()
 
- 可以自动扩展内存
 
3.4.1 声明
#ifndef STASH2_H #define STASH2_H class Stash{     int size;	      int quantity;     int next;	                unsigned char* storage;      void inflatte(int increase); public:     Stash(int size);     ~Stash();     int add(void * element);     void* fetch();     int count(); }; #endif
   | 
 
3.4.2 定义
#include "Stash2.h" #include "../require.h" #include <iostream> #include <cassert> using namespace std; const int increment = 100;
 
  Stash::Stash(int sz) {  	size = sz; 	quantity = 0; 	storage = 0; 	next = 0; } int Stash::add(void* element) {      	if(next >= quantity)  		inflate(increment); 	 	int startBytes = next * size; 	unsigned char* e = (unsigned char*)element; 	for(int i = 0; i < size; i++) 		storage[startBytes + i] = e[i]; 	next++; 	return (next - 1);  }
  void* Stash::fetch(int index) { 	require(0 <= index, "Stash::fetch (-)index");      	if(index >= next) return 0; 	 	return &(storage[index * size]); }
  int Stash::count() { 	return next;  }
  void Stash::inflate(int increase) { 	require(increase > 0, "Stash::inflate zero or negative increase");      	int newQuantity = quantity + increase; 	int newBytes = newQuantity * size; 	int oldBytes = quantity * size; 	unsigned char* b = new unsigned char[newBytes]; 	for(int i = 0; i < oldBytes; i++) 		b[i] = storage[i];  	delete[] (storage);  	storage = b;  	quantity = newQuantity; }
 
  Stash::~Stash() { 	if(storage != 0) {     	cout << "freeing storage" << endl;     	delete[] storage; 	} }
   | 
 
3.5 this
this:指向对象本身的指针,是类的每个成员函数的隐藏参数
void Stash::initialize(int sz);
  void Stash::initialize(Stash* this, int sz);
  Stash a; a.initialize(10);
  Stash::initialize(&a, 10);
   | 
 
class MyClass{     int x;     int y; public:     MyClass(){x = 0; y = 0;}     void foo(int x, int y){         this->x = x;         this->y = y;      } };
  | 
 
3.6 Object & class
Objects = Attributes + Services
- data:对象的特性or状态;operations:对对象的操作
 
- 通过接口修改数据,而非直接修改数据
 
- 直接访问变量,变量的声明者对变量没有控制权,无法控制操作者的行为
 

class定义object,object是class的一个实例
- class表述对象可能具有哪些特性
 
- object表示当前对象的每个特性的具体取值
 
OOP的特性:
- 所有事物均可以看作一个对象object
 
- 程序是对象的集合,他们通过互相发送消息,告知应该做些什么
 
- 每个对象都有自己独有的内存空间,由其他更加通用的对象组成
 
- 每个对象都有一个类型type
 
- 一个特定类型的所有对象,可以收到相同的信息
 
3.7 Definition of a class
- class的声明放入.h文件
 
- class的函数体、静态成员变量放入*.cpp文件
 
3.8 compile unit
- compiler只会看到当前的cpp文件,生成当前文件对应的
obj文件
 
- linker会链接所有的obj文件,生成一个
exe文件
 
- 如果要使用其它cpp文件中定义的函数/类,需要使用
.h头文件进行声明
 
- 如果函数定义在头文件,那么必须在任何使用该函数和定义该函数的地方include该头文件
 
- 如果class定义在头文件,那么必须在任何使用class和定义class的地方include该头文件
 
- 当使用
#include引用头文件时,编译器会将头文件的内容展开到当前文件,相当于将函数/类的声明写入了当前cpp文件中 

3.10 Makefile
- 当程序的代码量过大时,如果仅使用单个文件,会导致诸如难以管理、单次修改需要编译整个项目等问题
 
- 因此我们需要将代码拆分为多个文件进行管理与修改
 
- 多个代码文件之间的关系,通过Makefile文件声明
 
3.10.1 Project的结构
可以看作是一个有向无环图DAG
以一个工程为例
- 包含main.c、sum.c、sum.h
 
- sum.h在所有.c文件中都包含
 

此时的makefile为:
sum: main.o	sum.o 	gcc –o sum main.o sum.o main.o: main.c sum.h       gcc –c main.c sum.o: sum.c sum.h       gcc –c sum.c
   | 
 
3.10.2 makefile的语法规则:

简化语法:
sum: main.o	sum.o 	gcc –o $@ main.o sum.o  main.o	sum.o: sum.h       gcc –c $*.c 
   | 
 
3.10.3 makefile的过程
- 构建项目依赖树
 
- 创建第一条指令的目标,当且仅当一下两种情况成立之时:
- 目标文件不存在
 
- 目标文件比它的一个依赖项更早生成
 
 
- makefile的作用是保证最小的编译数量,因此需要正确写明
- 不要写成下面这样(这样写会直接重新编译所有文件)
 
 
prog: main.c sum1.c	sum2.c gcc –o prog main.c sum1.c sum2.c
   | 
 
3.11 CMake
- 是一个跨平台的,开源编译系统
 
- 可以看作是Makefile的升级版