课程代码
文件:string.h
#ifndef __MYSTRING__
#define __MYSTRING__
class String
{
public:
String(const char* cstr = 0);
String(const String& str);//拷贝构造,深拷贝,编译器默认是浅拷贝,Big three之一
String& operator=(const String& str)//拷贝赋值,big three之一
~String();//析构函数,big three之一
char* get_c_str() const {return m_data};//定义在类声明之中的成员函数将自动地成为内联函数
private:
char* m_data;//实现动态存储的效果
};
//String::function(...)
inline String::String(const char* sctr = 0)
{
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);//直接取另一个object的pointer,兄弟之间互为friend
}
//析构函数用于清理class中分配的堆内存
inline String::~String()
{
delete[] 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];//再分配和str.m_data一样大的堆内存空间
strcpy(m_data, str.m_data);//拷贝
return *this;//返回
}
//Global-function(...)
#endif
测试文件string-test.cpp
int main()
{
String s1();//无初值,涉及构造函数
String s2("hello");//有初值,涉及构造函数
String s3(s1);//拷贝,s3第一次重现
cout << s3 << endl;//<<重载
s3 = s2;//赋值,拷贝,注意此时s3不是第一次出现
cout << s3 << endl;
//以下艾为拷贝构造函数和拷贝赋值的调用
String s1("Hello");
String s2(s1);
String s2 = s1;//这句和上一句的意义是完全一样的
}
三大函数(BigThree):
Class with pointer member(s)
Big Three:拷贝构造(copy constructor),拷贝赋值(copy assignment operator),析构函数(destructor)
拷贝构造:
先构造再拷贝
一个构造函数传入的第一个参数是自身类型的引用,而且外参数都有默认值。
例如:
Rectangle(const Rectangle& other);
拷贝赋值:
它是对赋值运算符(=)的重载函数。
例如:
Rectangle& operator=(const Rectangle& other);
析构函数:
析构函数与构造函数相反,释放对象使用的资源。
例如:
~Rectangle();
所谓的栈(stack)和所谓的堆(heap)
Stack
, 是存在于某作用域(scope)的一块内存空间(memory space)。例如当你调用函数时,函数本身即形成一个stack用来放置它所接收的参数,以及返回地址。
在函数本体(function body)内声明的任何变量,其所使用的内存块都取自上述stack。
Heap
, 或谓之System heap, 是指由操作系统提供的一块global内存空间,程序可动态分配(dynamic allocated)从某种获得若干区块(blocks)。
堆和栈的区别
stack object
, 其生命在作用域(scope)结束之际结束。
这种作用域内的object, 又称为auto object, 因为它会被自动清理。
绝对不可以将指针指向栈对象。
heap object
,其生命周期在它被deleted之际结束。如果不delete就会发生内存泄露(memory leak),因为当作用域结束,heap object仍然存在,但是指针的生命周期已经结束了,也就是说指针本身是存在stack中的,因此作用域之外再也看不到指针也就没有机会释放指针指向的内存了。
类模版:
很多时候我们生成的类有很多共有的属性此时就可以生成一个模板类。
template <typename T>
class complex
{
public:
complex (T r = 0, T i = 0): re (r), im (i) { }
complex& operator += (const complex&);
T real () const { return re; }
T imag () const { return im; }
private:
T re, im;
friend complex& __doapl (complex *, const complex&);
};
{
complex c1<double> c1(2.1,2.2);
complex c2<int>(2,3);
...
}
函数模版:
template<class T>
inline
const T& min(const T& a,const T& b){
return b<a?b:a;
}
命名空间:
注意:不要在头文件中using 命名空间,会影响到使用头文件的程序
using namespace std
{
...
}
直接全部打开:
前置using namespace std;就可以使用命名空间所有名称
部分打开:
前置using std::cout;就可以在后面直接使用cout而不用提前申明了。