源碼
// 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;
}
學(xué)習(xí)到的知識
- 有指針成員變量的類旺上,一定要有拷貝構(gòu)造函數(shù)粪糙、拷貝賦值函數(shù)、析構(gòu)函數(shù)
原因是如果使用默認(rèn)的鸯两,那么只是淺拷貝闷旧。析構(gòu)函數(shù)是用來析構(gòu)分配的內(nèi)存的。如果不釋放分配的內(nèi)存那么會導(dǎo)致內(nèi)存泄漏的問題钧唐。
- 在拷貝賦值函數(shù)中一定要檢測鸠匀,這個(gè)值是不是自賦值
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 釋放掉逾柿,造成錯(cuò)誤的結(jié)果缀棍。
- delete vs delete[]
釋放的時(shí)候,如果創(chuàng)建的時(shí)候以一種數(shù)組的形式創(chuàng)建的那么一定要 delete[]机错。
- new 的本質(zhì)
先使用 malloc 分配內(nèi)存爬范,再調(diào)用構(gòu)造函數(shù)
- delete 的本質(zhì)
先調(diào)用析構(gòu)函數(shù),再釋放分配的內(nèi)存
- static 的成員變量要給初始值
#include <iostream>
using namespace std;
class Account {
public:
static double m_rate;
};
int main() {
Account a;
cout << a.m_rate << '\n';
return 0;
}
這樣寫會報(bào)錯(cuò)弱匪。
- static 成員函數(shù)調(diào)用方法有兩種青瀑,且沒有 this 指針
- 通過 object 調(diào)用
- 通過 class name 調(diào)用
#include <iostream>
using namespace std;
class A {
public:
static void foo(){
cout << "foo" << '\n';
}
};
int main() {
A::foo();
A a;
a.foo();
return 0;
}
- 類模板
就是在類的前面定義一個(gè)模板:
template<typename T>
class XXX{};
然后在類中就可以使用這個(gè)預(yù)定義的 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;
};
然后在使用的時(shí)候指定這個(gè)模板是什么萧诫。比如:
int main() {
Rectangle<double> r(1.1, 2.2);
cout << r.size() << '\n';
return 0;
}
- 函數(shù)模板
比如最小值(比 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;
}