主頁 > 軟體設計 > 【C++初階學習】C++string類的使用及模擬

【C++初階學習】C++string類的使用及模擬

2021-12-27 07:44:56 軟體設計

在這里插入圖片描述

【C++初階學習】string類

  • 零、前言
  • 一、什么是string類
    • 1、引入
    • 2、概念
  • 二、string類常用介面說明
    • 1、string類物件常見構造
    • 2、string類物件容量操作
    • 3、string類物件訪問及遍歷操作
    • 4、string類物件修改操作
    • 5、string類非成員函式
  • 三、模擬實作string類
    • 1、實作string類介面展示
    • 2、深淺拷貝問題
    • 3、string類深拷貝寫法
    • 4、string類其他常用介面模擬

零、前言

本章主要講解C++string類的相關知識以及使用,還會模擬實作一下string類

一、什么是string類

1、引入

C語言中,字串是以’\0’結尾的一些字符的集合,為了操作方便,C標準庫中提供了一些str系列的庫函式,但是這些庫函式與字串是分離開的,不太符合OOP的思想,而且底層空間需要用戶自己管理,稍不留神可能還會越界訪問,由此C++做出改進引入了string類

2、概念

  1. string是表示字串的字串類

  2. 該類的介面與常規容器的介面基本相同,再添加了一些專門用來操作string的常規操作

  3. string在底層實際是:basic_string模板類的別名

typedef basic_string<char, char_traits, allocator>string;
  1. 不能操作多位元組或者變長字符的序列

注:在使用string類時,必須包含

#include<string>
using namespace std;  

二、string類常用介面說明

注:下面講解最常用的介面

1、string類物件常見構造

函式名稱功能說明
string() (重點)構造空的string類物件,即空字串
string(const char* s) (重點)用C-string來構造string類物件
string(size_t n, char c)string類物件中包含n個字符c
string(const string&s) (重點)拷貝建構式
string (const string& str, size_t pos, size_t len = npos)從str物件中由pos位置開始截取len個長度的字符,len > str長度就結束
string (const char* s, size_t n)從s指向的字符陣列中復制前n個字符
  • 使用示例:
void Teststring1()
{
	// 構造空的string類物件,等同于string s1("");
	string s1; 
	// 用C格式字串構造string類物件s2
	string s2("hello cole"); 
	// 拷貝構造s3
	string s3(s2);
	// 截取string類部分拷貝
	string s4(s3, 6);//從第6個開始拷取到最后
	// 截取字符陣列部分拷貝
	char str[] = "hello cole";
	string s5(str, 5);//拷取前5個字符
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
}
// 注意:string類物件支持直接用cin和cout進行輸入和輸出
  • 結果:

在這里插入圖片描述

2、string類物件容量操作

函式名稱功能說明
size(重點)回傳字串有效字符長度
length回傳字串有效字符長度
capacity回傳空間總大小
empty (重點)檢測字串釋放為空串,是回傳true,否則回傳false
clear (重點)清空有效字符
reserve (重點)為字串預留空間**
resize (重點)將有效字符的個數該成n個,多出的空間用字符c填充
  • 使用示例1:
// size/clear/resize
void Teststring2()
{
	string s("hello cole!");
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
	// 將s中的字串清空,注意清空時只是將size清0,不改變底層空間的大小
	s.clear();
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 將s中有效字符個數增加到10個,多出位置用'a'進行填充
	// “aaaaaaaaaa”
	s.resize(10, 'a');
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 將s中有效字符個數增加到15個,多出位置用預設值'\0'進行填充
	// "aaaaaaaaaa\0\0\0\0\0"
	// 注意此時s中有效字符個數已經增加到15個
	s.resize(15);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
	// 將s中有效字符個數縮小到5個
	s.resize(5);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
}
  • 結果1:
    在這里插入圖片描述

  • 使用示例2:

//reserve
void Teststring4()
{
	string s;
	// 測驗reserve是否會改變string中有效元素個數
	s.reserve(100);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	// 測驗reserve引數小于string的底層空間大小時,是否會將空間縮小
	s.reserve(50);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}
  • 結果2:

在這里插入圖片描述

  • 使用示例3:
// 利用reserve提高插入資料的效率,避免增容帶來的開銷
void TestPushBack()
{
	string s;
	size_t sz = s.capacity();
	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}
void TestPushBackReserve()
{
	string s;
	s.reserve(100);
	size_t sz = s.capacity();
	cout << "capacity: " << sz << '\n';
	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}
  • 結果3:

在這里插入圖片描述

  • 注意:
  1. size()與length()方法底層實作原理完全相同,引入size()的原因是為了與其他容器的介面保持一致,一般情況下基本都是用size()

  2. clear()只是將string中有效字符清空,不改變底層空間大小

  3. resize(size_t n) 與 resize(size_t n, char c)都是將字串中有效字符個數改變到n個,不同的是當字符個數增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間

  • 注意:resize在改變元素個數時,如果是將元素個數增多,可能會改變底層容量的大小,如果是將元素個數減少,底層空間總大小不變
  1. reserve(size_t res_arg=0):為string預留空間,不改變有效元素個數,當reserve的引數小于string的底層空間總大小時,reserve不會改變容量大小

3、string類物件訪問及遍歷操作

函式名稱功能說明
operator[] (重點)回傳pos位置的字符,普通物件和const物件有相應的版本
begin+ endegin獲取第一個字符的迭代器 + end獲取最后一個字符下一個位置的迭代器
rbegin + rendbegin獲取第一個字符的迭代器 + end獲取最后一個字符下一個位置的迭代器
范圍forC++11支持,最終替換成迭代器
  • 使用示例:
void Teststring5()
{
	string s1("hello cole");
	//使用operator[]+size()遍歷字串
	for (size_t i = 0; i < s1.size(); i++)
	{
		//等同與s1.operator[](i)
		cout << s1[i] << " ";
	}
	cout << endl;
	//使用正向迭代器遍歷字串
	string::iterator it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;
	//注意:iterator為普通迭代器,可讀可寫,const_iterator為const迭代器,只能讀取字
	string::const_iterator it3 = s1.begin();
	while (it3 != s1.end())
	{
		//*it3+=1; 會報錯
		cout << *it3 << " ";
		it3++;
	}
	cout << endl;
	//使用反向迭代器遍歷字串
	string::reverse_iterator it2 = s1.rbegin();
	while (it2 != s1.rend())
	{
		cout << *it2 << " ";
		it2++;
	}
	cout << endl;
	//同樣的反向迭代器的const迭代器為const_reverse_iterator
	//范圍for遍歷字串
	for (auto e : s1)
	{
		cout << e << " ";
	}
}
  • 結果:

在這里插入圖片描述

4、string類物件修改操作

函式名稱功能說明
push_back在字串后尾插字符c
append在字串后追加一個字串
operator+= (重點)在字串后追加字串str
c_str(重點)回傳C格式字串
find + npos(重點)從字串pos位置開始往后找字符c,回傳該字符在字串中的位置
rfind從字串pos位置開始往前找字符c,回傳該字符在字串中的位置
substr在str中從pos位置開始,截取n個字符,然后將其回傳
  • 使用示例1:
void Teststring6()
{
	string str;
	cout << str << endl;
	str.push_back('c'); // 在str后插入字符
	cout << str << endl;
	str.append("hello"); // 在str后追加一個字符"hello"
	cout << str << endl;
	str += '\0'; // 在str后追加結束符
	str += "cole"; // 在str后追加一個字串"cole"
	cout << str << endl;//即使遇到‘\0’也不會停止,只有把字串給完全遍歷完了才會停止遍歷
	cout << str.c_str() << endl; // 以C語言的方式列印字串(遇到\0就停止)
}
  • 結果1:
    在這里插入圖片描述

  • 使用示例2:

void Teststring7()
{
	// 獲取file的后綴
	string file("string.cpp");
	size_t pos = file.rfind('.');//從后往前找字符. 
	string suffix(file.substr(pos, file.size() - pos));//拷貝pos位置之后的字串
	cout << suffix << endl;
    
	// 取出url中的域名
	string url("http://www.cplusplus.com/reference/string/string/find/");
	cout << url << endl;
	size_t start = url.find("://");//從前往后找字串 
	if (start == string::npos)//沒找到回傳npos
	{
		cout << "invalid url" << endl;
		return;
	}
	start += 3;
	size_t finish = url.find('/', start);//再往后找結束位置
	string address = url.substr(start, finish - start);//拷貝子串
	cout << address << endl;
    
	// 洗掉url的協議前綴
	pos = url.find("://");
	url.erase(0, pos + 3);
	cout << url << endl;
}
  • 結果2:

在這里插入圖片描述

注:npos是string里面的一個靜態成員變數

static const size_t npos = -1;
  • 注意:
  1. 在string尾部追加字符時,s.push_back? / s.append(1, c) / s += ‘c’ 三種的實作方式差不多,一般情況下string類的+=操作用的比較多,+=操作不僅可以連接單個字符,還可以連接字串

  2. 對string操作時,如果能夠大概預估到放多少字符,可以先通過reserve把空間預留好(提高效率)

5、string類非成員函式

函式功能說明
operator+盡量少用,因為傳值回傳,導致深拷貝效率低
operator>> (重點)輸入運算子多載
operator<< (重點)輸出運算子多載
getline (重點)獲取一行字串
relational operators (重點)大小比較

注:對上述函式只是了解一下,對于其他的操作函式可以查閱檔案了解

三、模擬實作string類

注:這里我們只是模擬實作string的一些常用介面,并非要完全復刻,學習下string類的底層,讓對string類的理解更深一點就行了

1、實作string類介面展示

注:模擬時為了避免與C++本身提供的string類造成命名沖突,我們選擇在命名空間里進行實作

namespace cole
{
    class string
    {
        friend ostream& operator<<(ostream& _cout, const cole::string& s);
        friend istream& operator>>(istream& _cin, cole::string& s);
        friend istream& getline(istream& _cin, string& s);

    public:
        typedef char* iterator;
        typedef const char* const_iterator;

        string(const char* str = "");
        string(const string& s);
        string& operator=(const string& s);
        ~string();
        void swap(string& s);
        // iterator
        iterator begin();
        iterator end();
        const_iterator begin()const;
        const_iterator end()const;

        // modify
        void push_back(char c);
        string& operator+=(char c);
        void append(const char* str);
        string& operator+=(const char* str);
        void clear();
        const char* c_str()const;

        // capacity
        size_t size()const;
        size_t capacity()const;
        bool empty()const;
        void resize(size_t n, char c = '\0');
        void reserve(size_t n);

        // access
        char& operator[](size_t index);
        const char& operator[](size_t index)const;

        //relational operator
        bool operator<(const string& s);
        bool operator<=(const string& s);
        bool operator>(const string& s);
        bool operator>=(const string& s);
        bool operator==(const string& s);
        bool operator!=(const string& s);

        // 回傳c在string中第一次出現的位置
        size_t find(char c, size_t pos = 0) const;
        // 回傳子串s在string中第一次出現的位置
        size_t find(const char* s, size_t pos = 0) const;
        // 在pos位置上插入字符c/字串str,并回傳該字符
        string& insert(size_t pos, char c);
        string& insert(size_t pos, const char* str);
        // 洗掉pos位置上的長度個字符
        string& erase(size_t pos, size_t len=npos);

    private:
        char* _str;
        size_t _capacity;
        size_t _size;
        static const size_t npos;
    };
    //初始化靜態私有成員變數
    const size_t string::npos = -1;
}

2、深淺拷貝問題

一般來說對于只有內置型別的成員變數,我們可以選擇編譯器提供的拷貝建構式和賦值多載函式(自己不寫),編譯器提供的這兩個函式能夠完成淺拷貝(拷貝值),但是對于存在指標成員變數的類,淺拷貝是不行的

  • 示例:
namespace cole
{

	class string
	{
	public:
		string(const char* str = "")
		{
			// 斷言不為空指標
			assert(str);
			_str = new char[strlen(str) + 1];
			strcpy(_str, str);
		}
		~string()
		{
			if (_str)
			{
				delete[] _str;
				_str = nullptr;
			}
		}
	private:
		char* _str;
	};
	// 測驗
	void Teststring()
	{
		string s1("hello cole");
		string s2(s1);
	}
}
int main()
{
	cole::Teststring();
	return 0;
}
  • 結果:

在這里插入圖片描述

  • 解釋:

在這里插入圖片描述

即值拷貝(淺拷貝)讓s1、s2共用同一塊記憶體空間,在釋放時同一塊空間被釋放多次而引起程式崩潰,由此對于涉及資源的管理,我們需要自己以深拷貝的方式寫拷貝建構式和賦值多載函式

3、string類深拷貝寫法

  • 深拷貝概念:

給每個物件獨立分配資源,保證多個物件之間不會因為共享資源而造成多種錯誤以及程式釋放崩潰的問題

  • 傳統式:比較常規,易于理解
class string
{
public:
    //建構式
    string(const char* str = "")
    {
        // 構造string類物件時,如果傳遞nullptr指標,認為程式非法,此處斷言下
        assert(str);
        _str = new char[strlen(str) + 1];
        strcpy(_str, str);
    }
    //拷貝建構式
    string(const string& s)
        : _str(new char[strlen(s._str) + 1])
    {
        strcpy(_str, s._str);
    }
    //賦值
    string& operator=(const string& s)
    {
        if (this != &s)//避免自己賦值自己(沒有意義)
        {
            delete[]_str;
            _str = new char[strlen(s._str) + 1];
            strcpy(_str, s._str);
        }
        return *this;
    }
    //解構式
    ~string()
    {
        delete[]_str;
        _str = nullptr;
    }
private:
    char* _str;
};
  • 現代式:簡潔,效果一致
class string
{
public:
	//建構式
	string(const char* str = "")
	{
		if (nullptr == str)//處理空指標
			str = "";
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	//拷貝構造
	string(const string& s)
		: _str(nullptr)//將自己賦值為空
	{
		string strTmp(s._str);//呼叫建構式,生成一個具有相同內容的string
		swap(_str, strTmp._str);//將string物件的各成員變數相互交換
	}//拷貝構造結束strTmp會先析構再銷毀

	//賦值多載
	string& operator=(string s)//傳值引數,會呼叫拷貝構造,生成一個具有相同內容的string
	{
		swap(_str, s._str);//將string物件的各成員變數相互交換
		return *this;
	}//賦值多載結束束s會先析構再銷毀

	//解構式
	~string()
	{
		delete[] _str;
		_str = nullptr;
	}
private:
	char* _str;
};

4、string類其他常用介面模擬

  • 實作代碼:
ostream& operator<<(ostream& _cout, const string& s)
{
    for (auto ch : s)//會替換成string的迭代器
    {
        _cout << ch;
    }
    return _cout;
}
istream& operator>>(istream& _cin, string& s)
{
    s.clear();//清理
    char ch;
    ch = _cin.get();//能夠接收空格和結束符
    while (ch != ' ' && ch != '\n')
    {
        s += ch;
        ch = _cin.get();
    }
    return _cin;
}

istream& getline(istream& _cin, string& s)
{
    s.clear();
    char ch;
    ch = _cin.get();
    while (ch != '\n')
    {
        s += ch;
        ch = _cin.get();
    }
    return _cin;
}
//建構式
string::string(const char* str="")
{
    if(str==nullptr)
        str="";
    _str = new char[strlen(str) + 1];
    _size = strlen(str);
    _capacity = _size;
    strcpy(_str, str);
}
//交換string
void string::swap(string& s)
{
    ::swap(_str, s._str);
    ::swap(_size, s._size);
    ::swap(_capacity, s._capacity);
}
//拷貝構造
string::string(const string& s)
    :_str(nullptr)
    , _size(0)
    , _capacity(0)
{
    string tmp(s._str);
    swap(tmp);
}
//賦值多載
string& string::operator=(const string& s)//傳參考
{
    //避免自己給自己賦值
    if (this != &s)
    {
        string tmp(s._str);
        swap(tmp);
    }
    return *this;
}
//解構式
string::~string()
{
    delete[] _str;
    _str = nullptr;
    _size = 0;
    _capacity = 0;
}

// iterator(普通物件)
string::iterator string::begin()
{
    return _str;
}
string::iterator string::end()
{
    return _str + _size;
}
// iterator(const物件)
string::const_iterator string::begin()const
{
    return _str;
}
string::const_iterator string::end()const
{
    return _str + _size;
}

// modify
//尾插字符
void string::push_back(char c)
{
    滿空間就擴容
    //if (_size == _capacity)
    //{
    //    reserve(_capacity == 0 ? 4 : _capacity * 2);
    //}
    //_str[_size] = c;
    //_size++;

    insert(_size, c);
}
string& string::operator+=(char c)
{
    push_back(c);
    return *this;
}
//追加字串
void string::append(const char* str)
{
    /*size_t len = _size + strlen(str);
    if (len > _capacity)
    {
        reserve(len);
    }
    strcpy(_str + _size, str);
    _size = len;*/

    insert(_size, str);
}
string& string::operator+=(const char* str)
{
    append(str);
    return *this;
}

void string::clear()
{
    _str[0] = '\0';
    _size = 0;
}

const char* string::c_str()const
{
    return _str;
}
size_t string::size()const
{
    return _size;
}
size_t string::capacity()const
{
    return _capacity;
}
bool string::empty()const
{
    return _size == 0;
}
//開空間+初始
void string::resize(size_t n, char c)
{
    if (n < _size)
    {
        _str[n] = '\0';
        _size = n;
    }
    else
    {
        if (n > _capacity)
        {
            reserve(n);
        }
        int pos = _size;
        while (pos < n)
            _str[pos++] = c;
        _str[n] = '\0';
        _size = n;
    }
}
//開空間
void string::reserve(size_t n)
{
    //需要的空間大于容量就開空間
    if (n > _capacity)
    { 
        char* tmp = new char[n + 1];
        strncpy(tmp, _str, _size + 1);//strcpy不能將\0后的內容也拷貝
        delete[] _str;
        _str = tmp;
        _capacity = n;
    }
}

// access
char& string::operator[](size_t index)
{
    assert(index < _size);
    return _str[index];
}
const char& string::operator[](size_t index)const
{
    assert(index < _size);
    return _str[index];
}

//relational operator
bool string::operator<(const string& s)
{
    return strcmp(_str, s._str) < 0;
}
bool string::operator<=(const string& s)
{
    return *this < s || *this == s;
}
bool string::operator>(const string& s)
{
    return !(*this <= s);
}
bool string::operator>=(const string& s)
{
    return !(*this < s);
}
bool string::operator==(const string& s)
{
    return strcmp(_str, s._str);
}
bool string::operator!=(const string& s)
{
    return !(*this == s);
}

// 回傳c在string中第一次出現的位置
size_t string::find(char c, size_t pos) const
{
    //pos的合理性
    assert(pos < _size);
    for (size_t i = pos; i < _size; i++)
    {
        if (_str[i] == c)
            return i;
    }
    //沒找到
    return npos;
}
// 回傳子串s在string中第一次出現的位置
size_t string::find(const char* s, size_t pos) const
{
    //pos的合理性
    assert(pos < _size);
    const char* ret = strstr(_str + pos, s);
    if (ret)
        return ret - _str;
    //沒找到
    return npos;
}
// 在pos位置上插入字符c/字串str
string& string::insert(size_t pos, char c)
{
    assert(pos <= _size);
    if (_size == _capacity)
    {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    char* end = _str + _size;
    while (end >= _str + pos)
    {
        *(end + 1) = *end;
        end--;
    }
    _str[pos] = c;
    _size++;
    return *this;
}
string& string::insert(size_t pos, const char* str)
{
    assert(pos <= _size);
    size_t len1 = strlen(str);
    size_t len2 = len1 + _size;
    if (len2 > _capacity)
    {
        reserve(len2);
    }
    char* end = _str + _size;
    while (end >= _str + pos)
    {
        *(end + len1) = *end;
        end--;
    }
    strncpy(_str + pos, str, len1);
    _size += len1;

    return *this;
}
// 洗掉pos位置上的長度個字符
string& string::erase(size_t pos, size_t len)
{
    assert(pos < _size);
    size_t leftlen = _size - pos - 1;
    if (len >= leftlen)
    {
        _str[pos] = '\0';
        _size = pos;
    }
    else
    {
        strcpy(_str + pos, _str + pos + len);
        _size -= len;
    }
    return *this;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/393976.html

標籤:其他

上一篇:詳談單元測驗

下一篇:【JavaWeb】【Java基礎I/O】 一文帶你搞懂檔案和JavaIO包下的File類~

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more