第二周
三大函数:拷贝构造,拷贝赋值,析构
字符串的构造函数,拷贝构造函数,
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<Complex*>(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
new一个Complex时,在调试模式下,会得左一的结果(每条代表4个字节),
- 灰色:系统内存
- 砖红色:cookie,记录整块内存大小,便于回收
- 浅绿色:对象的内存
- 深绿色:pad,补充内存(必须是16的倍数)
64的十六进制标识是40,此处cookie是41,最后一位表示这块内存是给出去还是收回来
release模式下分配内存为左2
动态分配得到的数组
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 <class T>
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 <<;