源碼
// 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;
}