Boolan/C++面向对象高级编程 part2

C++面向对象高级编程 part2

@(boolan C++)[C++]
2017-10-22 14:17:56 / helingchao


概述

本章节内容主要讲述如何设计class with pointer,以string为例。

#ifndef __MYSTRING__
#define __MYSTRING__

class String
{
public:                                 
   String(const char* cstr=0);                     
   String(const String& str);                    
   String& operator=(const String& str);         
   ~String();                                    
   char* get_c_str() const { return m_data; }
private:
   char* m_data;
};

#include <cstring>

inline
String::String(const char* cstr)
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}

inline
String::~String()
{
   delete[] m_data;
}

inline
String& String::operator=(const String& str)
{
   if (this == &str)
      return *this;

   delete[] m_data;
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}

#include <iostream>
using namespace std;

ostream& operator<<(ostream& os, const String& str)
{
   os << str.get_c_str();
   return os;
}

#endif


big three

所谓big three即:

  1. 拷贝构造
  2. 拷贝赋值
  3. 析构

1. 编译器提供的默认函数

声明一个空类

声明一个空类,如下:

class Empty {
}

C++会为上面定义的Empty类,提供默认的成员。效果等同于如下定义:

class Empty {
public:
Empty() {...};
~Empty(){...};
Empty(const Empty& rhs){...};
Empty& operatpr = (const Empty& rhs) {...};
}


C++提供的默认函数

  • default 构造函数
  • copy构造函数
  • 析构函数
  • copy assignment函数

原则 01: C++默认提供的函数仅在被调用时,编译器才会创建它们。
注意:这四个函数都是public和inline的。


默认函数的行为都是什么

default构造和析构函数

default 构造函数和析构函数主要是给编译器一个地方放置“藏身幕后”的代码。

  • default构造函数 :调用base classesnon-static 成员变量的构造函数。
  • 析构函数 :调用base classesnon-static 成员变量的析构函数。

注意: non-static成员的说法,static 类成员不在default构造函数的初始化范围内。

copy构造函数和copy assignment

单纯的将对象的每一个non-static成员拷贝到目标对象。

用户需要重新定义copy构造函数和copy assignment的场景

类中包含以下类型成员

  • 引用类型
  • 指针类型
  • const类型

2. 字符串设计

1509260994792.png
  1. 用指针保存存储数据的地址,不用数组。好处在于灵活的存储,无需考虑设计多大的数组。

实际是一种动态存储思想与静态存储思想之间的决策。

3. ctor & dtor

inline string::string(const char* cstr= 0) {
    if (cstr) {
        m_data = new char[strlen(cstr)+1];
        strcpy(m_data,cstr);
    }
    else {
        m_data = new char[1];
        m_data[0] = '\0';
    }
}

inline string::~string() {
    delete[] m_data;
}

字符串的两种形式:

  1. 串+‘\0’
  2. 长度字段+串

4. copy ctor & copy op =

1509261365517.png

浅拷贝 vs. 深拷贝

在copy对象时仅copy指针成员属于浅copy, 创建新的内存并将指针的内容copy到新内存是深copy。

在class with pointer 默认的copy ctor & copy op = 使用的是浅拷贝。

浅拷贝造成的问题:

浅拷贝会造成 alias(别名) 和 memory leak

alias 与 野指针/悬空指针

单一个内存单元被多个对象所只向时,可以看作是该内存单元存在了别名。

// p_a 与p_b 构成了alias 
int *p_a = new int();
int *p_b = p_a;

alias引入的问题:
内存单元被释放时,其他地点的别名可能不知道该内存以被释放,继而继续使用该内存,产生不确定的行为(undefined behavior)

1509262248771.png

什么是悬空指针(dangling pointer)?

If a pointer still references the original memory after it has been freed, it is called a dangling pointer.

悬空指针是指针最初指向的内存已经被释放了的一种指针。

什么是野指针(wild pointer)?

A pointer in c which has not been initialized is known as wild pointer.

野指针(wild pointer)就是没有被初始化过的指针.

5. 拷贝赋值/copy assignment operator

string& string::operator = (const string& str_r) {
    if (this == &str_r) {  // 自我检测
        return *this;
    }

    delete[] m_data;
    m_data = new char[strlen(str_r.m_data) + 1];
    strcpy(m_data, str_r.m_data);

    return *this;
}

注意⚠️:
拷贝赋值中的自我检测

copy op=的动作:

  1. 清空已有的数据
  2. 创建新内存
  3. 拷贝

拷贝构造与拷贝赋值的差别

  1. 拷贝构造是创建新对象,拷贝已有对象到新对象
  2. 拷贝赋值时,两个对象都已经被创建。

基于上述两点拷贝构造无需检测自我赋值,但拷贝赋值需要。


内存管理

1. stack vs. heap

1509263493997.png

stack, 是存在于某个作用域的一块内存空间。 例如函数被调用时,函数本身就会生成一个stack。

heap,是指由操作系统提供的一块gloabl内存空间,可由程序员动态创建。

2. static object & global object

两者在生命周期都是在main结束之后,程序结束之后才结束。

3. new: 先创建内存,后调用ctor

1509262367694.png

new的三个步骤

// 原始语句
complex* pc = new complex(1,2);
// 编译器内部转换后的遇见
void* mem = opreator new(sizeof(complex));  // 1. 分配内存
pc = static_cast<complex*>(mem);  // 2. 类型转化
pc->complex::complex(1,2);  // 3. 调用构造函数

成员函数的调用过程

哪个对象调用类成员函数,(编译器)默认将该对象的指针传给被调用成员函数this。

pc->complex::complex(1,2);

complex::complex(pc,1,2);

3. delete:先调用dtor, 后释放内存

1509262410676.png

4. array new 一定要搭配 array delete

1509262539128.png

扩展补充:类模版..

1. C++对象内存模型

  1. non-static 数据成员
  2. static 数据成员
  3. non-static 成员函数
  4. static 成员函数
1509263831824.png
  1. static 数据成员/static成员函数/none -static成员函数 全局只有一份。
  2. none-static数据成员每个对象各有一份

this指针

哪个对象调用成员函数,哪个对象的指针就会作为参数传递给成员函数的this指针

complex c1;
c1.real();
complex::real(&c1);
  1. none-static 成员函数通过this指针将处理不同对象的non-static数据。
  2. this pointer如何传递:non-static 成员函数是全局唯一的,哪个对象调用ns成员函数就将哪个对象的地址作为this指针传递给ns成员函数
1509262669674.png

static 成员

static成员脱离于对象。成员函数也是脱离于对象。

  1. static 成员函数没有this pointer
  2. st 成员函数只能处理 st数据
  3. st成员函数没有this指针所以不能处理非st数据

静态数据要在classbody外定义,定义时不要添加static声明。

class acount{
    static int a;
}

int acount::a;  // 类st成员定义
  1. st 成员数据要在class body 外“定义”。这里是定义,因为要分配内存。
  2. static 成员函数的两种调用方式:object调用,classname 调用。

设计static成员的原则

如果数据是在对象间通用的,则将该数据设计为类的static成员。

static 版本的singleton

class singleton {
public:
    static singleton& get_instance() {
        static singleton a;
        return a;
    }
private:
    singleton() {};
    
}

cout

1509263864546.png

class template

1509263880945.png

function template

1509263907947.png

argument deduction (实参推导):

  1. argument deduction (实参推导):不同于class template , function template 在使用时不用指定具体类型

名称空间

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容