三大函数:拷贝构造、拷贝赋值、析构
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;
};
如果所写的类中带有指针,不能使用编译器中自动生成的拷贝构造和拷贝赋值函数,必须自己重写一个。
堆、栈与内存管理
重载的operator<<函数必须是一个函数,不能写成一个成员函数,因为如果写成成员函数,<<在使用的时候必须在cout的左侧(<<cout)不符合用户的使用习惯,因此需要将其写成一个全局函数。
所谓stack(栈),所谓heap(堆)
stack:
存在于某个作作用域的一块内存空间。在函数体内声明的任何变量,其所使用的内存块都取自stack
Heap:
指由操作系统提供的一块global内存空间,程序可动态分配从某种获得若干区块。
local Object生命周期
class Complex{...};
...
{
Complex c1 (1, 2);
}
c1被自动释放
static local object生命周期
class Complex{...};
...
{
static Complex c1 (1, 2);
}
c2生命在作用域(scope)结束之后仍然存在,直到整个程序结束。
不带指针类的new和delete
new:
其中的opreator new()是C++中定义的一个特殊函数,在其内部中是调用malloc(n)函数进行内存的分配的。
delete:
同样的operator delete()是C++中的一个特殊函数,内部调用的free
带有指针类的new和delete
new:
delete:
image.png
调用析构函数的时候,会释放类中指针所占的内存。
动态分配所得到的内存块(memory block), in VC
image.png上面图片中,内存分配较多的是在debug模式下分配的内存。
橘色的部分是Cookie中存放的是内存释放时需要的信息,绿色的部分是复数对象所占用的内存,算出的内存是52,由于内存的总数是16的倍数,因而需要填充12bit的内存,一共为64。64写成16进制为00000040,由于是系统分配给对象的内存,因此橘色部分是末尾数字为1,00000041
动态分配所得的array
动态分配所得的arrayarray new 一定搭配array delete
如果一个类中含有指针成员,进行array new之后,必须搭配使用array delete否则会产生内存泄漏,其中泄漏的部分是,类中指针成员并没有得到释放,如果该类中不包含指针成员,是不会造成内存泄漏的。
第二周作业
#pragma once
#include <iostream>
class Shape
{
int no;
};
class Point
{
public:
Point(int x, int y) : x(x), y(y) {}
Point& operator=(const Point& point)
{
if (this == &point)
return *this;
this->x = point.x;
this->y = point.y;
}
~Point(){}
int getX() const { return this->x; }
int getY() const { return this->y; }
private:
int x;
int y;
};
class Rectangle : public Shape
{
int width;
int height;
Point * leftUp;
public:
Rectangle(int width, int height, int x, int y);
Rectangle(const Rectangle& other);
Rectangle& operator=(const Rectangle& other);
~Rectangle();
int GetWidth() const;
int GetHeight() const;
Point* GetPoint() const;
};
Rectangle::Rectangle(int width, int height, int x, int y)
{
this->width = width;
this->height = height;
leftUp = new Point(x, y);
}
Rectangle::Rectangle(const Rectangle & other)
{
this->width = other.width;
this->height = other.height;
this->leftUp = new Point(other.leftUp->getX(), other.leftUp->getY());
//this->leftUp = other.leftUp;
}
Rectangle& Rectangle::operator=(const Rectangle& other)
{
//判断地址是否相同
if (this == &other)
return *this;
this->width = other.width;
this->height = other.height;
this->leftUp = new Point(other.leftUp->getX(), other.leftUp->getY());
// 这种写法是错误的,这种写法会使得this->leftUp和other.leftUp指向同一个对象,
//当析构的时候就会出现问题,当其中的一个指针指向的内被释放时,那么另外一个指针就会成为野指针,再delete会崩溃
//this->leftUp = other.leftUp;
return *this;
}
Rectangle::~Rectangle()
{
delete leftUp;
}
int Rectangle::GetWidth() const
{
return this->width;
}
int Rectangle::GetHeight() const
{
return this->height;
}
Point* Rectangle::GetPoint() const
{
return this->leftUp;
}
std::ostream& operator<<(std::ostream& os, const Rectangle& rec)
{
os << rec.GetWidth() << rec.GetHeight()
<< rec.GetPoint()->getX()
<< rec.GetPoint()->getY();
return os;
}
static
上图中解释了this指针,cout << c1.real(); this指针相当于&c1。调用非静态成员函数,this指向的即为该调用者。
static
其中double Account::m_rate = 8.0;为静态成员变量的定义。
image.png
该模式为单例模式,由于构造函数是私有的,因而外界是不能创建对象的,成员A是静态的。
image.png
这种写法相对上面的好处是,上面一种静态变量一开始就占有着内存,而第二种只有创建对象的时候才会开始占有内存。
网友评论