博览网:C++开发工程师之面向对象高级编程(上)第二周笔记

7.Big Three:拷贝构造,拷贝赋值,析构

(1)什么时候需要自己写拷贝构造和拷贝赋值函数

当编译器提供的默认拷贝构造和拷贝赋值函数不再满足要求的时候,比方说类里面带指针,必须自己写拷贝构造和拷贝赋值函数;

String(constString& str);

String& operator=(constString& str);

如果不这么做,会怎么样?如图1所示,使用默认的拷贝构造和拷贝赋值函数,是一种浅拷贝,只会把指针拷贝过来,会造成内存泄漏,同时两个指针指向同一个地方,以后改动任何一个变量,会造成另外一个的改变。

                                                                                                         图 1

(2)怎么写拷贝构造和拷贝赋值函数

拷贝构造:①创造自己;②拷贝

拷贝构造函数,顾名思义就是拷贝和构造。拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的参数(对象的引用)是不可变的(const类型)。

如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数,这个默认的参数可能为X::X(const X&)或X::X(X&),

由编译器根据上下文决定选择哪一个,默认拷贝构造函数的行为如下:默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同

,执行先父类后子类的构造.拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise Copy)的动作.

a)如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数.

b)如果数据成员是一个数组,对数组的每一个执行按位拷贝.

c)如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符对其进行赋值

举例:

inline

String::String(constString& str)

{

m_data =newchar[strlen(str.m_data) + 1];

strcpy(m_data, str.m_data);

}

拷贝赋值:①delete自己;②重新创造自己;③拷贝

拷贝赋值函数参数跟拷贝构造函数相同,两者的区别在于:构造函数是对象创建并用另一个已经存在的对象来初始化它。

赋值函数只能把一个对象赋值给另一个已经存在的对象。

注意:考虑自我拷贝的情况

举例:

inline

String& String::operator =(constString& str)

{

if(this== &str)

return*this;

delete[] m_data;

m_data =newchar[strlen(str.m_data) + 1];

strcpy(m_data, str.m_data);

return*this;

}

(3)如果class里面有指针,多半要做动态分配

做了动态分配,则在创建的对象死亡之前析构函数会被调用起来;

8.堆,栈与内存管理

Stack(堆),是存在于某作用域(scope)的一块内存空间(memory space)。例如当你调用函数,函数本身会形成一个Stack用来放置它所接受的参数,以及返回地址。

在函数本体(function body)内声明的任何变量(local object),其所使用的内存块都取自上述Stack。

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

(1)stack objects的生命期

classComplex{...}

...

{

Complex c1(1,2);

}

c1便是所谓的Stack object,其生命在作用于(scope)结束之际结束。这种作用域内的object,又称为auto object,因为它会被自动清理;

(2)static local objects的生命期

classComplex {...}

...

{

staticComplex c2(1,2);

}

c2便是static object,其生命在作用域(scope)结束之后仍然存在,直到整个程序结束。

(3)global objects的生命期

classComplex {...}

...

Complex c3(1,2);

intmain()

{

...

}

c3便是所谓global object,其生命在整个程序结束之后才结束。也可以把它视为一种static object,其作用域是整个程序。

(4)heap objects的生命期

classComplex {...}

...

{

Complex* p=newComplex;

...

deletep;

}

p指的便是heap object,其生命在它被delete掉之后结束。如果没有delete p;会出现内存泄漏(memory leak),因为当作业域结束,p所致的heap object仍然存在,但指针p的生命却结束了,作用域之外再也看不到p(也就没有机会delete p)。

(5)new:先分配memory,再调用ctor

绝大部分编译器对调用new,转化为三步,详见图2

                                                                                                                   图 2

(6)delete:先调用dtor,再释放memory

                                                                                                    图 3

(7)动态分配所得的array

                                                                                                               图 4

(8)array new一定要搭配array delete

                                                                                                             图 5

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

(1)static

                                                                                                                图 6

类complex成员函数只有一份(不可能创建了几个对象就有几个函数),但是要处理很多对象,那就得靠this pointer来处理不同的对象。

而static的部分就和对象脱离了,它存在于内存的一部分,只有一份。

什么时候会使用static对象呢?就是和对象无关的部分。

staic成员函数和一般成员函数的特征就是static成员函数没有this pointer,既然没有this pointer,那static 成员函数不能和一般的函数一样去访问处理non-static data members,那只能处理static members

例如:

classAccount

{

public:

staticdoublem_rate;

staticvoidset_rate(constdouble& x) {m_data = x };

};

doubleAccount::m_rate = 8.0;//静态数据必须要这样定义,因为脱离对象,

intmain()

{

Account::set_rate(5.0);

Account a;

a.set_rate(7.0);

}

调用static函数有两种方法:

①通过object调用;

②通过class name 调用;

(2)Singleton模式(把ctors放在private区)

classA

{

public:

staticA& getInstance();

setup() {...}

private:

A();

A(constA& rhs);

staticA a;

...

};

A& A::getInstance()

{

returna;

}

a本来就存在,和对象无关,然后不想其他人创建,那就把构造函数放在private里,那怎么取得a呢,就用个static A& getInstance()取得a,这是与外界的接口。但这不是最好的写法,因为不管你用不用,a都存在。所以更好的写法如下:

classA

{

public:

staticA& getInstance();

setup() {...}

private:

A();

A(constA& rhs);

...

};

A& A::getInstance()

{

staticA a;//只有当有人掉用这个函数,a才会存在

returna;

}

(3)cout

                                                                                                                    图 7

可以看出cout就是一种ostream,实际上是重载了<<运算符的函数,用于打印不同类型的数。

(4)class template,类模板

template

classcomplex

{

public:

complex (T r = 0, T i = 0)

: re (r), im(i)

{}

complex& operator += (constcomplex&);

T real()const{returnre; }

T imag()const{returnim; }

private:

T re, im;

friendcomplex& _doapl (complex*,constcomplex&);

};

//调用如下

{

complex c1(2.5,1.5);

complex c2(2,6);

}

(5)function template函数模板

classstone

{

public:

stone(intw,inth,intwe)

: _w(w), _h(h), _weight(we)

{}

booloperator < (conststone& rhs)const

{return_weight < rhs._weight; }

private:

int_w, _h, _weight;

};

template

inlineconstT& min(constT& a,constT& b)

{

returnb < a ? b : a;

}

//使用

stone r1(2,3), r2(3,3), r3;

r3 = min(r1,r2);//则会调用min函数,函数里面会接着调用stone::operator<函数

(6)namespace

以防和别人写的东西重名。

使用方法有两种:

①using directive

usingnamespacestd;//把namspace空间的东西全打开

cin >> i;

cout <<"hello"<< endl;

②using declaration

usingstd::cout;

std::cin >> i;

cout <<"hello"<< endl;

不要在头文件中使用using namespace std;,容易造成命名空间污染;

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

推荐阅读更多精彩内容