Boolan C++面向对象高级编程(上)第二周笔记

来源:互联网 发布:类似爱情2只有我知结局 编辑:程序博客网 时间:2024/05/19 22:57

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

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

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

String(const String& str);String& operator=(const String& str);


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


                                                                      图 1

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

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

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


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

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

inlineString& 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;}

(3)如果class里面有指针,多半要做动态分配
做了动态分配,则在创建的对象死亡之前析构函数会被调用起来;


8.堆,栈与内存管理

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

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

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

(1)stack objects的生命期

class Complex{...}...{Complex c1(1,2);}

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


(2)static local objects的生命期

class Complex {...}...{static Complex c2(1,2);}

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


(3)global objects的生命期

class Complex {...}...Complex c3(1,2);int main(){...}

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


(4)heap objects的生命期

class Complex {...}...{Complex* p=new Complex;...delete p;}

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

例如:

class Account{    public:    static double m_rate;    static void set_rate(const double& x) {m_data = x };};double Account::m_rate = 8.0;   //静态数据必须要这样定义,因为脱离对象,int main(){    Account::set_rate(5.0);    Account a;    a.set_rate(7.0);}
调用static函数有两种方法:
①通过object调用;
②通过class name 调用;


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

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

class A{    public:        static A& getInstance();        setup() {...}    private:        A();        A(const A& rhs);        ... };A& A::getInstance(){    static A a;   //只有当有人掉用这个函数,a才会存在    return a;}

(3)cout


                                                                                 图 7

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


(4)class template,类模板

template<typename T>class complex{    public:        complex (T r = 0, T i = 0)        : re (r), im(i)        {}        complex& operator += (const complex&);        T real() const {return re; }        T imag() const {return im; }    private:        T re, im;        friend complex& _doapl (complex*, const complex&);};//调用如下{    complex<double> c1(2.5,1.5);    complex<int> c2(2,6);}

(5)function template函数模板

class stone{    public:    stone(int w, int h, int we)    : _w(w), _h(h), _weight(we)    {}    bool operator < (const stone& rhs) const    { return _weight < rhs._weight; }    private:        int _w, _h, _weight;};template<class T>inline const T& min(const T& a, const T& b){    return b < a ? b : a; }//使用stone r1(2,3), r2(3,3), r3;r3 = min(r1,r2);  //则会调用min函数,函数里面会接着调用stone::operator<函数

(6)namespace

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

使用方法有两种:

①using directive

using namespace std; //把namspace空间的东西全打开cin >> i;cout << "hello" << endl;
②using declaration

using std::cout;std::cin >> i;cout << "hello" << endl;

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

0 0
原创粉丝点击