第二周主要学习的是 class with pointer member,通过以String Class的设计来学习
String类最后要实现如下功能
String s1 ();
String s2 ("hello");
String s3 (s1); // 拷贝构造
s3 = s2; // 拷贝赋值
编译器会给每个类默认提供拷贝构造和拷贝赋值的函数,通过一个byte一个byte的拷贝。而对于类中有指针的情况,需要自己来实现这两个函数,避免和新产生的对象指向堆中内存的同一个地址
Big Three 三个特殊函数
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;
};
下面来看各个函数的实现
// 构造函数
inline String::String(const char *cstr) {
if (cstr) {
m_data = new char[strlen(cstr) + 1];
strcpy(m_data, cstr);
} else {
m_data = new char[1];
*m_data = '\0';
}
}
// 拷贝构造
inline String::String(const String &str) {
m_data = new char(strlen(str.m_data) + 1);
strcpy(m_data, str.m_data);
}
// 拷贝赋值
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;
}
// 析构函数
inline String::~String() {
delete[] m_data;
}
最后为了方便输出String,重载<<操作符
std::ostream& operator << (std::ostream &os, const String &str) {
os<<str.get_c_str();
return os;
}
堆、栈 内存管理
{
Complex c1(1, 2); // 这种方式变量是创建在函数的栈上的
Complex* p = new Complex(3); // 创建一个复数,初值是3,而值是创建在堆上的,动态获得,需要手动释放
}
stack object 的生命周期:只要离开作用域,就结束了。c1便是stack object,又称为auto object,因为它会被『自动』清理
static local object的生命周期:如果在c1前加上static关键字,则其在离开作用域后仍然存在,直到整个程序结束
global object 的生命周期:在任何大括号之外的地方声明的,也可视为一种static object,在整个程序结束后被清理
heap object 的生命周期:其生命在被delete时结束,如果忘记delete,将会造成memory leak,当作用域结束,指针所指向的heap object仍然存在,但指针的生命已经结束了
new: 先分配memory,再调用ctor
new 操作编译器将会分解为3个动作,1. 分配内存 2. 对指针做类型转换 3. 执行构造函数
delete: 先调用dtor,再释放memory
delete 操作编译器将会分解为2个动作,1. 执行dtor 2. 释放内存
补充的知识点
- static
类中数据和函数前,均可添加static关键字
non static member function,编译器会自动给一个this pointer,而static member function 是没有的,所以static member function 不能使用non static member data,只能处理static member data
static member data 需要申明,static member function的调用可以通过两种方式 1. 通过class name调用 2. 通过object 调用
通过static来实现单例模式栗子
class A{
public:
static A& getInstance() {
static A instance;
return instance;
};
void setup();
private:
A();
A(const A& other);
};
A::getInstance().setup();
cout
在c++源码中发现,在ostream中对各种常见的类型做了重载,正是因为如此,cout才可以接受那么多种类型并能打印出来class template 和 function template
之后模板的课程里会详细讲解