七、三大函数
拷贝构造、拷贝赋值、析构
1、string class(带指针)
class String
{
public:
String(const char* cstr = 0); //构造,没有返回类型
String(const String& str); //拷贝构造
String& operator=(const String& str);//拷贝赋值,
//能否传回引用,看函数执行的结果放到什么地方去,放进去的地方是不是local object,
//只要不是就传reference,此处赋值目的端本来就存在,并不需要在函数operator=里创建,所以可以
~String();
char* get_c_str() const {return m_data;}//函数没有改动数据,所以加const
private:
char* m_data; //放一个指针,32位系统中占4个字节
};
class里面有指针,多半要做动态分配,那么对象死亡之前,析构函数会被调用,释放动态分配的内存。
构造函数:
inline
String::String(const char* cstr = 0)
{
if(cstr){ //传进来非空
m_data = new char[strlen(cstr)+1]; //数组
strcpy(m_data, cstr);
}
else{ //未指定初值,是空的,0
m_data = new char[1];
*m_data = '\0'; //把自己准备为一个空字符串,只有一个结束符
}
}
inline //因为函数体简单,加上
String::~String(){
delete[] m_data;
}
{
String s1(),
String s2("hello");
String* p = new String("hello");
delete p;
}
2、class with pointer members必须有copy构造和copy op=(assignment operator)
浅拷贝:两个指针指向同一块内存,易造成内存泄露(编程里别名是一个危险的事)
深拷贝:两个空间内容相同。拷贝构造函数,收到的参数就是自己的类型
拷贝构造函数:
inline
String::String(const String& str){
m_data = new char[strlen(str.m_data)+1];
strcpy(m_data, str.m_data);
}
3、copy assignment operator
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;//当有一连串赋值的时候要用//传出去的人不必知道接收端用什么接收
}
八、堆、栈与内存管理
1、Stack
存在于某作用域(scope)的一块内存空间(memory space),例如当你调用函数,函数本身即会形成一个stack用来放置它所接收的参数,返回地址,以及local object
- c1即是栈对象,生命在大括号—作用域(scope)结束之际结束,又称auto object.
- c2即静态对象,生命在作用域结束之后仍然存在,直到整个程序结束
- 全局对象,生命在整个程序结束之后才结束
class Complex{..};
..
{
Complex c1(1,2); //栈
static Complex c2(1,2);
Complex* p = new Complex(1,2); //堆,需自己手动delete
..
delete p;
}
2、Heap
操作系统提供的一块global内存空间,程序可动态分配若干区域
- 不delete时出现内存泄露,因为当作用域结束,p所指的heap object仍然存在,但指针p的生命却结束了,作用域之外再也看不到p, 也就没机会delete p;
- new: 先分配memory,再调用拷贝构造函数
pc->Complex::Complex(1,2);
谁调用谁就是那个this.Complex::Complex(pc,1,2)
,pc就是this
因为Complex类里面,数据只有实部、虚部两个private 的double类型,那么new出来的就是8字节大小的内存(一个double大小4个字节)
- 复数里面没有指针,也不做动态分配
- string类为一个指针,4个字节
- delete: 先调用析构函数(一,把字符串里面的动态分配的那一块杀掉,清除指针指向的内存),再释放memory(二、把字符串本身(就是一个指针)清掉)
class String
{
public:
~String(); //一
{delete[] m_data;}
..
private:
char* m_data; //二
};
array new一定搭配array delete.
String *p = new String[3]; ... delete[] p;
九、复习string类的实现过程
十、扩展:类模板、函数模板及其他
1、static
静态函数只能处理静态数据
- 单例模式,一旦有人用一次这个单例才会存在,并且永远只有这一个
2、cout
3、类模板
4、函数模板
编译器会做实参推导(argument deduction),将template< class T>中T自动转化为实际的类,但是类需要自己写好函数中需用到的操作符重载
5、namepace
将东西包在一个namespace里面
十一、组合和继承
1、Composition(复合),表示has-a
- Adapter 设计模式
- 成员变量、函数等
2、Delegation. Composition by reference(即使用指针传,也叫by reference)
-
即两个类之间用指针相连,所以生命不同步,任何需要的时候创建,方便日后的更改,也方便共享
-
包含一个指针指向为我实现所有功能的那一个类
3、Inheritance(复合),表示is-a
十二、虚函数与多态
十三、委托相关
原型prototype