第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的升级版