美文网首页
GeekBand C++面向对象高级编程(上) 笔记&心得 2(

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

作者: 复杂也不复杂的Mr囚 | 来源:发表于2016-10-16 17:59 被阅读0次

    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:拷贝构造函数是新建一块内存空间来存放新的内容。也就是值拷贝。拷贝的是内容。

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

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

    使用默认的拷贝赋值会发生的危险

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

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

    拷贝赋值函数的编写

    8.堆,栈与内存管理

    8.1      堆  栈

    堆和栈的定义

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

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


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

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

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

    8.2      static  object     global object   heap object

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

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

    Q:两者有什么区别??

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

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

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

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

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

    A:


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

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


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

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

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

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

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

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

    举个栗子:

    静态对象的声明定义

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

    Singleton设计模式:

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

    Singleton较差的实现 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()的时候在被创建。这样使得程序的执行有更高的效率。

    模板:

    模板涉及比较浅不细说。

    类模板 函数模板

    命名空间:

    比较浅不细说。

    命名空间的使用

    11.组合与继承

    举个课件里的栗子:

    类的组合
    类的组合2

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

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

    依旧是课件:

    委托(Delegation)

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

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

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

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


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

    继承(Inheritance):


    继承的使用方法(黄色部分)
    继承下的构造和析构



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

    虚函数:

    虚函数的分类

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


    留下的小问题的程序结构

    A:下面是我的答案:


    这里是代码 这里是答案

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


    而另一个问题:

    问题

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


    答案

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

    举个栗子:

    观察者设计模式

    观察者模式资料:

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

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

    Prototype设计模式:

    创建一个未来的对象。

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

    代码:

    Prototype框架图 代码1 代码2 代码3

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

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

    总结一下:

    了解到的方法:

    1.Adapter

    Adapter

    2.Handle/Body

    Handle/Body(pImpl)

    3.Template Method

    Template Method

    4.Observer

    Observer

    5.Prototype

    Prototype

    几种面向对象的方法:

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


    以上。

    相关文章

      网友评论

          本文标题:GeekBand C++面向对象高级编程(上) 笔记&心得 2(

          本文链接:https://www.haomeiwen.com/subject/yobuyttx.html