通過 String 類學習的知識

源碼

// 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 指針
  1. 通過 object 調用
  2. 通過 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;
}

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容