GeekBand C++ week 2

字数 2022阅读 74

1.String class (class with pointers)

'=' 赋值方式实现指针copy

copy构造(接受同类作为初值)和 copy赋值(赋值右操作数是同类)不写的话也存在,每bit复制(编译器提供的)。

数据是一个指针,需要时再动态分配空间

接口:构造函数对不同输入操作符重载

析构函数:~+class name, 当一个类对象结束生命时调用(即程序执行离开作用域时)

Big Three: copy构造、copy赋值、析构函数

2.ctor和dtor(构造函数 和 析构函数)

new/delete == malloc()/free() 内存泄漏 动态分配而不释放相应内存

注:“hello”作为初值并不内含'\0',应在初始化时增加

3.class with pointer members必须有copy ctor和copy op=

如果使用default copy ctor或default op=是浅copy,只修改指针的值(因为字符串实际存储位置并不在对象内,使得内存泄露,而内存中仍只有一份数据副本) 出现alias(叠名,多名称指向同一内存空间很危险)

深copy,清除原来的无用数据空间 ,分配新的存储空间,来建立副本。

在copy op=时,注意检查自我赋值(小心alias,提高效率,防止副本在复制前被删除,产生未知bug)

复习 为了避免重载‘<<'时改变方向,要声明为全局函数,以免对象默认作用于左值, ostream要作为左值。

4.Stack(栈)&Heap(堆) scope(作用域)

Stack是存在于某作用域(scope)的一块内存空间会形成一个stack以放置它所接收的参数,local(auto) object,以及返回地址

Heap,或system heap,是指由操作系统提供的一块global内存空间,程序可动态分配(dynamic allocated)从某中获得若干区块(blocks)

5.objects的生命期 何时调用相应析构函数

stack(auto) 在作用域结束之际结束;

static local objects 在整个程序结束时结束;

global objects 在整个程序结束时结束,可视为一种特殊的static object;

heap objects 在它被deleted之际结束。

6.new 先分配memory,再调用ctor

void *mem = operator new(sizeof(type)); //分配内存 内部调用malloc(n)

pc = static_cast(mem); //类型转换

pc->type::type(arg); //构造函数 => Complex::Complex(pc, 1, 2) pc是ctor作为成员函数的this指针

7.delete 先调用dtor,再释放memory

type::~type(pc); //析构函数

opetator delete(pc); //释放内存

8、动态分配所得的内存块(memory block)

(system)cookie +(Debug header 32bytes+) 所需内存 + (no man land 4 +)(pad 4*n +)(system)cookie

cookie(4byte)以标志分配区块大小和状态

因为VC中都为16的倍数,所以cookie最后一个byte的低四位总是0,因此可以用最低位借位表示1已分配和0未分配

动态分配所得array(array new搭配array delete)

(system)cookie +(Debug header 32bytes + )元素数标志(int 4byte) + 所需内存 + (no man land 4 +)(pad 4*n +)(system)cookie

未搭配情况,会使得析构函数不正确调用,使得array内动态分配去泄露

补充内容

1)static 通过传入this pointer使得同一个成员函数处理不同的对象,而不会出现多个重复函数单一处理各自对象,静态函数没有this pointer只能处理静态数据。static数据全类唯一,并通过类外赋值完成初始化,初始化要在实现中进行。静态函数既可被对象作为成员函数调用,也可以作为类成员函数直接调用。

静态函数和静态数据成员都不是对象成员而属于类的静态成员,静态成员访问可以在类中进行,对非静态成员则只能通过对象。

singleton模式,以static方式(类中副本单一)

2)cout 进行了大量的<<操作符的重载,一种ostream

3)class template 对同一实现成员不同的情况进行代码重用 template 使用时:class

function template 对同一实现成员不同的情况进行代码重用 template 使用时不必显式声明,编译器对function template可以进行参数推到(argument deduction)

4)namespace + 名称,把所有用到的东西封装在一个namespace里,以免重名产生的错误。多文件写std在编译时会被组合到一起。

使用方式

using directive 将封装完全打开,e.g. using namespace std;

using declaration 逐条声明 e.g. using std::cout;

直接写出全名 e.g. std::cin >> ...;

面向对象编程 探讨类和类之间的关系

1.Inheritance(继承) is a关系

三种继承方式

:public 父类(Base)的数据是被子类(Derived)完整继承的,子类中含有父类的成分;和虚函数搭配体现价值;

函数的继承继承的是调用权;在子类对象中调用父类函数是一种常见现象。把父类的强关联函数,放到具体子类中实现,建立Template Method实现。一般性操作建立Application framework,使专业人员能集中处理核心问题。成员函数内调用函数仍由this作为参数调用。

构造由内而外:Derived::Derived(...): Base() {...};

构造由外而内:Derived::~Derived(...) {...~Base() };

base class 的dtor必须是virtual,否则会出现undefined behavior。

:protected

:private

Inheritance(继承) with virtual functions(虚函数) override(仅用于虚函数被重新定义,覆写)

non- virtual function: 你不希望derived class override它

virtual function:你希望derived class override它,且你对它已有默认定义 virtual 标识符

pure virtual function:你希望derived class一定要override它,你对它没有默认定义 virtual 函数声明 =0

Inheritance + Composition 关系下的构造和析构

//Derived 同时含有 Composition的component情况

Derived::Derived(...):Base(), Component() {...} 构造由内而外

Derived::~Derived(...):{...~Component(), ~Base()}; 析构由外而内

Delegation + Inheritance 尤其用在user interface

Subject(数据存储)-建立vector-> Observer(数据展示)

多种展示方式作为Observer的子类。

2.Composition(复合) has a关系,引用其它结构/类型作为成员。

Adaptor:通过复合一个强功能的结构,然后开放部分功能(即构建一个adaptor),来使之符合使用要求。

Container -> Component

Container构造时由内而外,先调用Component的default构造函数,然后才执行自己;

Container析构时由外而内,首先执行自己,然后才调用Component的析构函数。

以上都是编译器补充的,实际构造析构并不需要明文写出。

如果编译器提供的默认方式不合意,请自行编写构造函数。

3.Delegation(委托)/Composition by reference

用指针的方式实现has,而不是直接含有相应对象,需要时指针才有所指(不同步)。

pointer to implementation/Handle & Body 用指针指向实现,可以方便的切换实现,亦称编译防火墙。

reference counting 内容共享特性,特别注意,共享时修改要copy on write即修改时提供新的副本给对象进行修改。

4.设计模式


容器里放的东西一定要一样大小,因此推荐指针作为容器参量。add 以指向父类的指针进行操作,使得两种子类都可以进行add 操作。


现在去创建未来的对象,每一个子类创建自己,被之前的父类看到,子类把自己的原型置入父类的相应空间。

推荐阅读更多精彩内容