GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)

7.三大构造函数:拷贝构造,拷贝赋值,析构函数

Class With Pointer member(s) :要写析构函数,而析构函数主要的作用就是删除新建的内存空间,删除不再使用的指针指向的不再使用的Object

String类讲解代码的Part:

String(const char* cstr=0);             //构造函数,默认将cstr的初始值赋为0

String(const String& str);                //拷贝构造,将参数str的m_data拷贝。深拷贝,自己创建一块内   存空间将str的m_data重新拷贝一份。因为它是接受自己(String)这种东西,所以是拷贝构造

String& operator=(const String& str);  // 拷贝赋值。

~String();

char* get_c_str() const { return m_data; }

Q:为什么我需要重新写拷贝构造和拷贝赋值??

A:因为编译器使用的默认的拷贝构造和拷贝赋值是使用值的,而不知指针的。所以当我们使用带指针的时候一定要自己写拷贝构造和拷贝赋值。

Q:拷贝构造函数    VS   拷贝赋值函数   两者有什么区别??

A:拷贝构造函数是新建一块内存空间来存放新的内容。也就是值拷贝。拷贝的是内容。

      拷贝赋值函数是拷贝的地址。也就是位拷贝。当其中一个对象修改的时候另外的一个也会随之变化。

       第二个例子就是使用编译器默认的拷贝赋值,可以看到发生了内存泄露。

GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第1张图片
使用默认的拷贝赋值会发生的危险

  这里有个相关内容的BLOG地址:http://www.cnblogs.com/kaituorensheng/p/3245522.html

来看看拷贝赋值函数的编写:

GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第2张图片
拷贝赋值函数的编写

8.堆,栈与内存管理

8.1      堆  栈

GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第3张图片
堆和栈的定义

堆必须使用new来动态分配内存,使用delete删除。

栈是比较小的,如果什么东西都使用栈来存储可能会发生爆栈的情况。例如:


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第4张图片

在全局变量中声明,使用堆来存储


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第5张图片
在局部变量中声明,使用栈来存储

在第一种情况中内存发生了溢出而中止了程序,第二种情况则正常编译成功。

说明使用堆相比于使用栈不那么容易发生溢出,它取决于你内存的大小。

8.2      static  object     global object   heap object

static object静态对象在函数作用域执行完之后仍然存在于程序中没有被销毁,直到程序执行完之后才消失。

global object是全局对象,到程序执行完之后才消失。

Q:两者有什么区别??

A:区别在于global object更早地被创建(在程序的一开始),而静态对象则是在执行到指定的语句的时候才被创建。

heap object是堆对象,它和上面两个没有那么像。其生命周期是在new创建时开始,在delete删除时结束。记住new后必须delete删除,否则会发生内存泄露。

8.3编译器如何创建删除对象的


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第6张图片


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第7张图片


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第8张图片


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第9张图片

可以知道,构造函数是从外而内构造的,而析构函数是从内而外析构的。

Q:为什么array new 要对于 array delete

A:

GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第10张图片


这张图可以知道如果使用delete只能删除一个dtor,而使用array delete才能删除三个dtor。这样才不会发生内存泄露。

10. 补充拓展:类模板,函数模板以及其他


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第11张图片

函数是如何如何处理到不同的对象的

从图中可以看到,通过this指针来指向不同的对象来告诉函数要处理什么对象数据。

静态函数:静态函数没有this pointer,所以静态函数只能处理静态数据

Q:静态函数什么时候用?好处有什么?

A:不用实例化;      被预编译;      访问速度比较快。

http://www.cnblogs.com/devinzhang/archive/2012/04/27/2473570.html

举个栗子:


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第12张图片
静态对象的声明定义

可以看到,在类外一定要加上double Account::m_rate = 8.0;

Singleton设计模式:

使用静态实现的设计模式。非常有意思。来看看代码:


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第13张图片
Singleton较差的实现


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第14张图片
singleton较好的实现

Singleton设计模式将类的实例化使用static完成并如果调用只调用一次。
下面摘抄百度知道的一个回答:

static关键字至少有下列作用:

(1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;

(2)在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问。

(3)在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;

(4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;

(5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

上面(较差)和下面(较好)的区别在于一个把static A a放在private区,另一个放在了getInstance()区。为什么放在getInstance区叫好呢? 因为如果放在private区不论如何都被创建了,而放在getInstance()区只有在调用getInstance()的时候在被创建。这样使得程序的执行有更高的效率。

模板:

模板涉及比较浅不细说。


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第15张图片
类模板


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第16张图片
函数模板

命名空间:

比较浅不细说。


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第17张图片
命名空间的使用

11.组合与继承

举个课件里的栗子:

GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第18张图片
类的组合


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第19张图片

类的组合2

可以看到queue中包含了deque,而deque中又包含了Itr,这就是一次类的组合(Composition)。

下面再来介绍一个特性:委托(Delegation)

依旧是课件:


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第20张图片
委托(Delegation)

Q:什么使用用组合什么时候用继承呢?

A:优先使用对象组合,而不是类继承

Q:委托和组合有什么区别呢?

A:从课件中可以看到,委托其实就是Composition by Reference(学术界只说by reference不说by pointer。。。。so。。。。)。使用引用的组合。委托是对一个类的功能进行扩展和复用的方法。它的做法是:写一个附加的类提供附加的功能,并使用原来的类的实例提供原有的功能。扩展和复用一个类的功能常用的一种方法是继承,而另一种更普遍的方法则是委托。在很多情况下委托很适用,而继承则并不适用。


pimpl(Handle/Body)实现方法:图左边(String.hpp)提供一个借口,而具体实现方式在(String.cpp)的实现方法就叫做pimpl。又叫做编译防火墙(左边不用编译只要编译右边)。

继承(Inheritance):


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第21张图片

继承的使用方法(黄色部分)


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第22张图片

继承下的构造和析构



继承下的构造和析构还是特别容易理解,不细说。

虚函数:


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第23张图片
虚函数的分类

Q:侯老师留的一个小问题,Derived是Base的子类,又和Component组合,而Base和Component之间没有任何关系,探究这样子的一个结构中构造函数和析构函数的调用顺序


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第24张图片

留下的小问题的程序结构

A:下面是我的答案:


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第25张图片

这里是代码


这里是答案

可以看到编译器先构造了Base,然后构造了Component,最后才构造了Derived。紧接着最先析构了Derived,接着析构了Component,最后析构了Base。我们可以知道编译器首先构造父类的对象,接着构造了组合类的对象,最后才构造了自己。而这也是合乎逻辑的。


而另一个问题:


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第26张图片
问题

这个问题很明白,从内而外构造是Component,Base,Derived。而析构时相反顺序的。


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第27张图片

答案

委托+继承的方法(最强大的!):

举个栗子:

GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第28张图片
观察者设计模式

观察者模式资料:

http://www.cnblogs.com/wangjq/archive/2012/07/12/2587966.html

http://lavasoft.blog.51cto.com/62575/201617/

Prototype设计模式:

创建一个未来的对象。

说明: #(protected)   -(private)   下划线(静态)  没有标记=(+)也就是公有的

代码:


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第29张图片
Prototype框架图


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第30张图片
代码1


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第31张图片
代码2


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第32张图片
代码3

简单说就是通过复制一份已经存在的实例来建立一个新的实例(未来的实例)。原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据。

http://blog.csdn.net/hguisu/article/details/7518947

总结一下:

了解到的方法:

1.Adapter


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第33张图片
Adapter

2.Handle/Body

GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第34张图片
Handle/Body(pImpl)

3.Template Method


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第35张图片
Template Method

4.Observer


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第36张图片
Observer

5.Prototype


GeekBand C++面向对象高级编程(上) 笔记&心得 2(1)_第37张图片
Prototype

几种面向对象的方法:

复合  继承   委托   继承+委托     继承+虚函数


以上。

你可能感兴趣的:(GeekBand C++面向对象高级编程(上) 笔记&心得 2(1))