C++面向对象高级编程(上)-第二周-博览网

第二周

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

字符串的构造函数,拷贝构造函数,

int main()
{
    String s1();
    String s2("hello");

    String s3(s1);      ///调用拷贝构造函数
    cout << s3 << endl;

    s3 = s2;            ///s2赋值给s3,拷贝赋值函数

    cout << s3 << endl;
}

拷贝构造函数和拷贝赋值函数没有自主定义时,编译器会给出默认,默认按位拷贝,成员带有指针时,只拷贝指针内容,两个指针指向同一地方。

类内带指针时,要自己定义拷贝构造和拷贝赋值函数

class String
{
public:
    String(const char * cstr = 0);
    String(const String & str);     ///参数为本类
    String& operator=(const String & cstr);     ///参数为本类
    ~String();
    char* get_c_str() const {return m_data;}
private:
    char* m_data;       ///动态分配
};
inline
String::String(const char* cstr = 0)
{
    if (csrt)
    {
        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;    ///不delete 内存泄漏
}

字符串的表示方式:

  • 不知道长度,但是最后有\0;

  • 没有结束符号,但是有长度声明

delete 与delete[]

class with pointer members 必须有copy ctor 和copy op=

默认拷贝是不会拷贝动态分配的内存的

String a("Hello");
String b("Wworld");
b = a;      ///浅拷贝,别名

copy ctor(拷贝构造函数)

inline
String::String(const String & str)
{
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data,str.m_data);  //直接取另一个object的private成员
}
{
    String s1("Hello");
    String s2(s1);
    //String s2 = s1;
}

拷贝赋值函数

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

一定要在operator= 函数中检查是否self assignment

stack(栈)和heap(堆)

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

在函数本体(function body)内声明的任何变量,其所使用的内存块都取自stack

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

class Complex{....};

{
    Complex cl(1,2);        //空间来自stack
    Complex* p = new Complex(3);  //Complex(3)是个临时对象,其所占用的
                             ///空间是new自heap的动态分配而得,并由p指向
}

stack object的声明周期

c1就是stack object,其声明在作用域(scope)结束之际结束,这种作用域内的object,又称为auto object,因为它会被“自动”清理(自动调用析构)

static local objects的声明周期

class Complex{...};

{
    static Complex c2(1,2);
}

c2 就是static object ,其生命在作用域结束之后仍然存在,直到整个程序结束(静态对象)

global object

class Complex{...};

Complex c3(1,2)

{
    .....
}

c3便是global object ,其生命在整个程序之后结束,作用域是整个程序

heap objects 的生命周期

class Complex{...};


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

p所指的便是heap object,其生命在它被deleted之际结束

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

以上出现内存泄漏(memory leak),因为当作用域结束,p所指向的heap object仍然存在,但指针p的生命却结束了,作用域之外再也看不到p(也就没有了栈会delete p)

new:先分配memory,再调用ctor

Complex* pc = new Complex(1,2);

编译器转化为:

Complex *pc;
    void* mem = operator new(sizeof(Complex));  //分配内存,内部调用malloc(n)
    pc = static_cast(mem);            //转型
    pc->Complex::Copmlex(1,2);                  //构造函数

delete :先调用dior,在释放memory

Complex* pc = new Complex(1,2);
...
delete pc;

编译器转化为:

Complex::~Complex(pc);  //析构函数
operator delete(pc);    //释放内存,内部调用free
String* pc = new String("Hello");
...
delete ps;

被编译器转化为:

String::~String(ps);    ///析构函数,删除自分配的内存
operator delete(ps);    ///释放内存,杀掉字符串

动态分配所得的内存块(memory block),in VC

C++面向对象高级编程(上)-第二周-博览网_第1张图片
VS分配内存块

new一个Complex时,在调试模式下,会得左一的结果(每条代表4个字节),

  • 灰色:系统内存
  • 砖红色:cookie,记录整块内存大小,便于回收
  • 浅绿色:对象的内存
  • 深绿色:pad,补充内存(必须是16的倍数)

64的十六进制标识是40,此处cookie是41,最后一位表示这块内存是给出去还是收回来

release模式下分配内存为左2

动态分配得到的数组

C++面向对象高级编程(上)-第二周-博览网_第2张图片
VS动态分配数组

Complex * p = new Complex[3];//debug时对应左一

  • 白色:用一个整数记录长度
  • 浅灰色:三个Comlex

String* p=new String[3]; ///对应右二

new与delete成对使用

new[]与delete[]成对使用

内存泄漏时,cookie之间的内存不会泄漏,但是当写为delete[]时,编译器才会调用多次析构函数,释放各自对象分配的内存,否则只会调用一次析构函数

类模板、函数模板、及其他

static

静态数据与静态函数

只有一份在内存里,静态函数没有this指针,只能处理静态数据

class Account
{
public:
    static double m_rate;   //声明
    static void set_rate(const double& x){m_rate = x;}
}
double Account::m_rate = 8.0;   //定义,初始化

int main()
{
    Account::set_rate(5.0);  //通过object调用
    Account a;          //通过class name调用
    a.set_rate(7.0);
}

调用static函数的方法

  • 通过object调用

  • 通过class name调用

把ctor放在private区 Singleton

class A
{
public:
    static A& getInstance()
    setup(){...}
private:
    A();
    A(const A& ths);
    static A a;
    ...
}

A& A::getInstance()
{
    static A a;
    return a;
}

A::getInstance().setup();

函数模板

stone r1(2,3),r2(3,3),r3;
r3 = min(r1,r2);        ///T为stone,则调用stone::operator<

template 
inline
const T& min(const T& a,const T& b)
{
    return b < a ? b : a;
}

class stone
{
public:
    stone(int w,int h,int we):_w(), _h(h), _we(we){}
    bool operator< (const stone& rhs) const{return _we < rhs._we;}
private:
    int _w, _h, _we;
}

namespace

//using directive
using namespace std;

//using declaraion
using std::cout;
std::cin << ...;
cout << ...;

//
std::cim <<;
std::cout <<;

你可能感兴趣的:(C++面向对象高级编程(上)-第二周-博览网)