源码
// string.h
#ifndef __MYSTRING__
#define __MYSTRING__
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;
};
#include <cstring>
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()
{
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 ];
strcpy(m_data, str.m_data);
return *this;
}
inline
String::String(const String& str)
{
m_data = new char[ strlen(str.m_data) + 1 ];
strcpy(m_data, str.m_data);
}
#include <iostream>
using namespace std;
ostream& operator<<(ostream& os, const String& str)
{
os << str.get_c_str();
return os;
}
#endif
// string_test.cpp
#include "string.h"
#include <iostream>
using namespace std;
int main()
{
String s1("hello");
String s2("world");
String s3(s2);
cout << s3 << endl;
s3 = s1;
cout << s3 << endl;
cout << s2 << endl;
cout << s1 << endl;
}
学习到的知识
- 有指针成员变量的类,一定要有拷贝构造函数、拷贝赋值函数、析构函数
原因是如果使用默认的,那么只是浅拷贝。析构函数是用来析构分配的内存的。如果不释放分配的内存那么会导致内存泄漏的问题。
- 在拷贝赋值函数中一定要检测,这个值是不是自赋值
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;
}
比如如果是自赋值的话,上面的代码会把自己的 m_data 释放掉,造成错误的结果。
- delete vs delete[]
释放的时候,如果创建的时候以一种数组的形式创建的那么一定要 delete[]。
- new 的本质
先使用 malloc 分配内存,再调用构造函数
- delete 的本质
先调用析构函数,再释放分配的内存
- static 的成员变量要给初始值
#include <iostream>
using namespace std;
class Account {
public:
static double m_rate;
};
int main() {
Account a;
cout << a.m_rate << '\n';
return 0;
}
这样写会报错。
- static 成员函数调用方法有两种,且没有 this 指针
- 通过 object 调用
- 通过 class name 调用
#include <iostream>
using namespace std;
class A {
public:
static void foo(){
cout << "foo" << '\n';
}
};
int main() {
A::foo();
A a;
a.foo();
return 0;
}
- 类模板
就是在类的前面定义一个模板:
template<typename T>
class XXX{};
然后在类中就可以使用这个预定义的 T。比如:
template<typename T>
class Rectangle{
public:
Rectangle(const T w = 0, const T h = 0):w(w),h(h){}
T size() {
return w * h;
}
private:
T w, h;
};
然后在使用的时候指定这个模板是什么。比如:
int main() {
Rectangle<double> r(1.1, 2.2);
cout << r.size() << '\n';
return 0;
}
- 函数模板
比如最小值(比 go 真的简单太多了)
#include <iostream>
#include <utility>
using namespace std;
template<class T>
inline
const T& myMin(const T& x, const T& y) {
return x < y ? x : y;
}
class Stone{
public:
Stone(const double size, string name):size(size),name(std::move(name)){}
inline bool operator<(const Stone& s) const {
return this->size < s.size;
}
inline string get_name() const{
return this->name;
}
private:
string name;
double size;
};
inline ostream& operator<<(ostream& os, const Stone& s) {
os << s.get_name();
return os;
}
int main() {
cout << myMin(1.1, 2.2) << '\n';
cout << myMin(Stone(10, "min_stone"), Stone(20, "big_stone")) << '\n';
return 0;
}