【C++技能树】String类解析与模拟实现

简介: 终于放假啦,停更了一个月的博客也要重新拾起来了。近一个月都没怎么好好写代码,现在好多都看不懂了。在接下的时间里,会更新:算法题,ROS,C++,Linux相关内容。

Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我bua!

终于放假啦,停更了一个月的博客也要重新拾起来了。近一个月都没怎么好好写代码,现在好多都看不懂了。在接下的时间里,会更新:算法题,ROS,C++,Linux相关内容。



a44904b2b84a45b7b63cfd04d97ba59f.png


String


1.String常用接口


String字符串是标准命名空间std的下的一个类。头文件为。是一个表示字符序列的类。学习STL模板库可以参考这个网站,自行查看传入参数以及返回参数等相关内容


1.1构造函数


constructor(构造函数),用于初始化string类对象。有以下几种函数重载:


default (1) string();
copy (2) string (const string& str);
substring (3) string (const string& str, size_t pos, size_t len = npos);
from c-string (4) string (const char* s);
from sequence (5) string (const char* s, size_t n);
fill (6) string (size_t n, char c);


我们仅介绍常用的,也就是:默认构造(1),拷贝构造(2)从const char*中构造string类,FILL(6)。

1.先来看看默认构造函数:


string s1;


这样就直接创建了一个空的String类对象s1,之后可以再用s1调用string类的接口


2.之后是拷贝构造函数:


cpp中类进行拷贝构造需要调用拷贝构造函数,传入参数都是const class&(具体为什么已经在之前介绍过了,忘记的可以看看这篇文章:  拷贝构造).


string (const string& s);
string s3(s2);


这里用s2对s3进行初始化.


3.从const char*中构造string类:


string (const char*);
string s2("hello world");


out:hello world


4.string类中包含n个字符c:


string (count,char);
string s4(5,'c');


out:ccccc


5.截取一定长度的字符:


第三个和第五个其实大差不差,虽然相较于第三个,第五个参数少了一个.但可以理解为,第五个是从0位置开始截取,而第三个是从pos位置开始截取.也可以说第三个是第五个构造函数的升级.(顺带一提在STL中,POS表示位置:position,LEN表示长度:length).


当然第五个只适用于char*,而第三个适用于string.有点绕,就是这两个没有什么必然的联系,理解起来可以按上面的来理解.


第三个:


string (const string& str, size_t pos, size_t len = npos);
string s2("hello world");
string s6(s2,6,-1);


out:world


第五个:


string (const char* s,size_t n);
string s5("hello world",5);


out:world


代码总览:


void constructor()
{
    string s1;
    string s2("hello world");
    string s3(s2);
    string s4(5,'c');
    string s5("hello world",5);
    string s6(s2,6,-1);
    cout<<"s1:"<<s1.c_str()<<endl;
    cout<<"s2:"<<s2.c_str()<<endl;//hello world
    cout<<"s3:"<<s3.c_str()<<endl;//hello world
    cout<<"s4:"<<s4.c_str()<<endl;//ccccc
    cout<<"s5:"<<s5.c_str()<<endl;//hello
    cout<<"s6:"<<s6.c_str()<<endl;//world
}


1.2 容量操作


接下来我们来看看,有关String类的相关的容量操作.这里先提几个点:


1.size_t为无符号整数,在32位系统下为unsigned int.在64位系统下为unsigned long.

2.npos为-1,在其与size_t比较时,进行整形提升,表示为size_t最大的位置.所以通常情况下npos表示一个不存在的位置

3.与C语言不同,C中的字符串char*以’\0’来判断结束,而string类以当前pos与size的关系(==)来判断该字符串是否结束

1.2.1 size()与length()


size_t size() const;
size_t length() const;


Return length of string 返回字符串长度


这两个函数完全相同,引入size只是为了和其他STL容器接口保持一致.所以我们看size即可.


string s1("hello");
cout<<s1.size()<<endl;
cout<<s1.length()<<endl;


out:5

这里回顾下之前提到的第三点:'\0’的问题


string s1("hello");
s1+='\0';
s1+="!!!!!!!!";
cout<<"s1.size():"<<s1.size()<<endl;
const char * ch="hello'\0'!!!!!!!!";
cout<<"const char *:"<<strlen(ch)<<endl;


out:s1.size():14

out:const char* len:6


可以明显看出区别,这在之后模拟实现string会有大问题.


1.2.2 capacity()


size_t capacity() const;


Return size of allocated storage


每一段字符串系统都会为他提前开辟好一段空间,而capacity则是返回这段空间的大小.


string s1("hello");
cout<<"s1.capacity():"<<s1.capacity()<<endl;


out:15


表示最开始时系统为s1这个字符串分配了15bit的空间


在不同的平台下,系统初始分配空间与每次扩容的大小是不同的.


1.2.3empty()


bool empty() const;


Returns whether the string is empty (i.e. whether its length is 0).


若string为空则返回true,否则返回false


string s1;
cout<<"s1.empty()"<<s1.empty()<<endl;
s1+="hello";
cout<<"s1.empty()"<<s1.empty()<<endl;


out:s1.empty():1

out:s1.empty():0


1.2.4clear()


void clear();


无返回值,清楚string中的所有字符,令其size=0,但不改变已经分配的capacity


string s1("hello");
cout<<"s1:"<<s1<<endl;
cout<<"s1.size:"<<s1.size()<<endl;
cout<<"s1.capacity:"<<s1.capacity()<<endl;
s1.clear();
cout<<"s1:"<<s1<<endl;
cout<<"s1.size:"<<s1.size()<<endl;
cout<<"s1.capacity:"<<s1.capacity()<<endl;


out: s1:hello

s1.capacity:15

s1:

s1.size:0

s1.capacity:15


1.2.5 reserve()与resize()


reserve():


void reserve (size_t n = 0);


改变capacity的大小,若n小于capacity则不改变,大于则不改变有效元素的个数仅扩充空间

string s1("hello");
cout<<"s1.capacity:"<<s1.capacity()<<endl;
s1.reserve(s1.capacity()-2);
cout<<"s1.capacity:"<<s1.capacity()<<endl;
s1.reserve(s1.capacity()+2);
cout<<"s1.capacity:"<<s1.capacity()<<endl;


out: s1.capacity:15

s1.capacity:15

s1.capacity:30


至于为什么最后一次不是17而是30,是这样解释的:


If n is greater than the current string capacity, the function causes the container to increase its capacity to n characters (or greater).

也就是会扩充到更大,至于大多少是由操作系统/编码平台来决定的.


resize():


void resize (size_t n);
void resize (size_t n, char c);


Resizes the string to a length of n characters.调整string长度为n的有效字符


有两个函数重载:当n<size时,则两个函数相同都为缩减size=n,当size>n时,第一个函数会用0来填充多出来的长度.而第二个函数会用c来填充.


string s1("hello");
cout<<"s1.size:"<<s1.size()<<endl;
s1.resize(4);
cout<<"s1:"<<s1<<endl;
s1.resize(3,'c');
cout<<"s1:"<<s1<<endl;
s1.resize(8);
cout<<"s1:"<<s1<<endl;
s1.resize(16,'c');
cout<<"s1:"<<s1<<endl;


out: s1.size:5

s1:hell

s1:hel

s1:hel

s1.length():8

s1:helcccccccc


填充后的0是不显示的,但是存在的.


reserve与resize的区别:


先来看看下面这个代码有什么问题:


#include<iostream>
#include<string>
using namespace std;
int main()
{
    string s1;
    s1.reserve(10);
    for(int i=0;i<10;i++)
    {
        s1[i]='a';
    }
}


这个问题之前提到过:reserve是改变capacity,而通过[]去访问string需要size在这个范围里,也就是有效字符数在这个范围里.


#include<iostream>
#include<string>
using namespace std;
int main()
{
    string s1;
    s1.resize(10);
    for(int i=0;i<10;i++)
    {
        s1[i]='a';
    }
}


1.2 类对象的访问及遍历操作


支持[]访问、迭代器(begin,end)与反向迭代器(rebegin,rend)


迭代器在这里可以看成一个指针,重点在实现string类中才会涉及。所以我们简单演示一下.


#include<iostream>
#include<string>
using namespace std;
int main()
{
    string s1("hello");
    string::iterator begin=s1.begin();
    string::iterator end=s1.end();
    for(;begin!=end;begin++)
    {
        cout<<*begin;
    }
}


out:hello


#include<iostream>
#include<string>
using namespace std;
int main()
{
    string s1("hello");
    string::reverse_iterator rbegin=s1.rbegin();
    string::reverse_iterator rend=s1.rend();
    for(;rbegin!=rend;rbegin++)
    {
        cout<<*rbegin;
    }
}


out:olleh


1.3 string对象的修改操作


push_back() 尾插一个字符
append() 尾插
operator+= 尾插
c_str 返回C格式的字符串
find+npos pos开始往后找字符,返回位置
rfind 从pos往前找字符,返回位置
substr 从pos开始截取n个字符,然后返回


1.3.1 push_back()


void push_back (char c);


Appends character c to the end of the string, increasing its length by one.


将一个字符插入到队尾,并将其长度+1


string s1;
s1.push_back('a');
cout<<"s1:"<<s1;


**out: **s1:a


1.3.2 append()与 operator+=


append:


string (1) string& append (const string& str);
substring (2) string& append (const string& str, size_t subpos, size_t sublen);
c-string (3) string& append (const char* s);
buffer (4) string& append (const char* s, size_t n);
fill (5) string& append (size_t n, char c);


其函数重载较多,我们也不都演示了.之前有过看源码的经历,所以较为轻松的能看出来每一个在干嘛:


(1) string


Appends a copy of str.


(2) substring


Appends a copy of a substring of str. The substring is the portion of str that begins at the character position subpos and spans sublen characters (or until the end of str, if either str is too short or if sublen is string::npos).


(3) c-string


Appends a copy of the string formed by the null-terminated character sequence (C-string) pointed by s.


(4) buffer


Appends a copy of the first n characters in the array of characters pointed by s.


(5) fill


Appends n consecutive copies of character c.


  1. 将一个string对象追加到队尾
  2. 将一个string对象从pos位置开始截取len个长度追加到队尾
  3. 将C格式的字符追加到队尾
  4. 将C格式的字符从0开始截取n个字符追加到队尾
  5. 将string队尾追加n个c字符

string s1;
s1.append("hello");
string s2;
s2.append(s1,1,-1);
cout<<"s1:"<<s1<<endl;
cout<<"s2:"<<s2<<endl;
string s3;
s3.append("const char *");
cout<<"s3:"<<s3<<endl;
string s4;
s4.append("const char *",5);
cout<<"s4:"<<s4<<endl;


out: s1:hello

s2:ello

s3:const char *

s4:const


operator+=:


是push_back与append的结合,既能追加单个字符也可以是一个string类型或是const char*


string s5;
s5+="h";
s5+="ello";
string s6(" world");
s5+=s6;
cout<<"s5:"<<s5<<endl;


out:s5:hello world


1.3.3 c_str()


const char* c_str() const;


将string对象转换成const char*并返回


    string s1("hello");
    cout<<s1.c_str();


out:hello


这个函数的意义是:C++需要兼容C语言,很多接口只能读取C的char*类型,例如ROS中的消息传递,所以需要这么个函数.函数不复杂,但意义重大


1.3.4find()


string (1) size_t find (const string& str, size_t pos = 0) const noexcept;
c-string (2) size_t find (const char* s, size_t pos = 0) const;
buffer (3) size_t find (const char* s, size_t pos, size_type n) const;
character (4) size_t find (char c, size_t pos = 0) const noexcept;


也是拥有多个重载:


1.在string中寻找与之匹配的string,从pos开始寻找

2.string变为了const char* 其余与(1)相同

3.在(2)的基础上截取const char*的前n个作为查找对象

4.在string中寻找char,从pos位置开始寻找


若找到则返回对应位置,未找到则返回npos

string s1("hello hello world");
string s2("hello");
size_t pos=s1.find(s2);
cout<<"first s2 at:"<<pos<<endl;
pos=s1.find(s2,pos+1);
cout<<"second s2 at:"<<pos<<endl;   
pos=s1.find("hello");
cout<<"first hello at:"<<pos<<endl;
pos=s1.find("hello",pos+1);
cout<<"second hello at:"<<pos<<endl;   
pos=s1.find("hello",0,1);
cout<<"first h at:"<<pos<<endl;


out: first s2 at:0

second s2 at:6

first hello at:0

second hello at:6

first h at:0


rfind是从pos位置往前找:

string (1) size_t rfind (const string& str, size_t pos = npos) const noexcept;
c-string (2) size_t rfind (const char* s, size_t pos = npos) const;
buffer (3) size_t rfind (const char* s, size_t pos, size_t n) const;
character (4) size_t rfind (char c, size_t pos = npos) const noexcept;


除了默认参数不同,其他都是相同的.这里就不演示了


1.3.5 substr()


string substr (size_t pos = 0, size_t len = npos) const;


Returns a newly constructed string object with its value initialized to a copy of a substring of this object.


返回一个对原字符串截取完的拷贝字符串.(所以是不会改变原字符串)


从pos位置开始截取len个长度


string s1("hello world");
string s2(s1.substr(6,-1));
cout<<"s2:"<<s2<<endl;


out: world


2. String的模拟实现


为了避免与库函数的string产生命名冲突,我们需要新建一个命名空间,在新的命名空间中模拟String:


namespace H{
    class mystring{
    }
}


2.1 私有属性


private:
      char* _str;
      size_t _size;
      size_t _capacity;
      const static size_t npos;
    const size_t mystring::npos = -1;


其有四个私有属性:


  1. _str表示字符串的内容
  2. _size表示当前字符串有效长度
  3. _capacity表示当前字符串所占空间大小
  4. npos表示size_t的最大值

2.2构造函数 析构函数 拷贝构造函数


构造函数:


mystring(const char* str="")
        :_str(new char[strlen(str) + 1])
        , _size(strlen(str))
        , _capacity(_size)
      {
        strcpy(_str, str);
      }


注意:使用初始化列表需要与私有属性声明顺序要保持一致

拷贝构造函数:


mystring(const mystring& str)
      {
        _str = new char[str._capacity + 1];
        //strcpy(_str, str._str);
        memcpy(_str, str._str, str._size + 1);
        _capacity = str._capacity;
        _size = str._size;
      }


这里不用strcpy,因为新加入的字符可能是’\0’,用strcpy会导致在’\0处’就停止.


析构函数:

~mystring() {
        delete[]_str;
        _size = _capacity = 0;
      }


2.3 c_str()与size()


const char* c_str()const
{
    return _str;
}
size_t size()const
{
    return _size; 
}


2.4 operator[]


char& operator[](size_t pos)
{
    assert(_size > pos);
    return _str[pos];
}
const char& operator[](size_t pos)const
{
    assert(_size > pos);
    return _str[pos];
}


2.5 iterator


在这里 迭代器iterator可以直接看成一个指针,所以使用之前我们要进行一个typedef:


typedef char* iterator;
typedef const char* const_iterator;


之后就是正常的指针用法


iterator begin()
{
    return _str;
}
iterator end()
{
    return _str + _size;
}
const_iterator begin() const
{
    return _str;
}
const_iterator end()const
{
    return _str + _size;
}


写完迭代器后范围for就可以使用啦~


2.6 reserve()


void reserve(size_t n)
{
    if (n > _capacity)
    {
        char* tmp = new char[n + 1];
        memcpy(tmp, _str, _size + 1);
        delete[]_str;
        _str = tmp;
        _capacity = n;
    }
}


这里也不能用strcpy.


2.7 push_back()


void push_back(char ch)
{
    if (_size == _capacity)
    {
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    }
    _str[_size] = ch;
    _str[++_size] = '\0';
}


2.8 append()


void append(const char* str)
{
    size_t len = strlen(str);
    if (_size + len >= _capacity)
    {
        reserve(_size+len);
    }
    strcpy(_str + _size, str);
    _size += len;  
}


先判断下是否会超过当前的capacity


2.9 operator +=


mystring& operator+=(const char str)
{
    push_back(str);
    return *this;
}
mystring& operator+=(const char* str)
{
    append(str);
    return *this;
}


2.10 insert()


void insert(size_t pos, size_t n, char ch)
{
    assert(pos <= _size);
    if (_size + n > _capacity)
    {
        reserve(_size + n);
    }
    int  end = _size;
    while (end >= pos&&end!=npos)
    {
        _str[end + n] = _str[end];
        end--;
    }
    for (size_t i = 0; i < n; i++)
    {
        _str[pos + i] = ch;
    }
    _size += n;
}
void insert(size_t pos, const char * ch)
{
    size_t len = strlen(ch);
    assert(pos<=_size);
    if (_size+len > _capacity)
    {
        reserve(_size +len);
    }
    int  end = _size;
    while (end >= pos && end != npos)
    {
        _str[end + len] = _str[end];
        end--;
    }
    for (size_t i = 0; i < len; i++)
    {
        _str[pos + i] = ch[i];
    }
    _size += len;
}

eacf5d6b3bb04b208c4ba993367357bb.jpg


2.11 erase()


void erase(size_t pos, size_t len = npos)
{
    assert(pos <= _size);
    if (len == npos || pos + len >= _size)
    {
        _str[pos] = '\0';
        _size = pos;
    }
    else
    {
        size_t end = pos + len;
        while (end <= _size)
        {
            _str[pos++] = _str[end];
            end++;
        }
        _size -= len;
    }
}

536d83ee93d842e5ad876e2ba8ecb548.jpg


2.12 find()


    size_t find(char ch,size_t pos=0)
    {
        for (size_t i = pos; i < _size; i++)
        {
            if (_str[i] == ch)
            {
                return i;
            }
        }
        return npos;
    }
    size_t find(const char* str, size_t pos = 0)
    {
        assert(pos < _size);
        const char* ptr = strstr(_str+pos, str);
        if (ptr)
        {
            return ptr - _str;
        }
        else
            return npos;
    }


2.13 substr()


mystring substr(size_t pos = 0, size_t len = npos)
{
    size_t n = len;
    if (len == npos || pos + len > _size)
    {
        n = _size - pos;
    }
    mystring tmp;
    tmp.reserve(n);
    for (size_t i = pos; i < n+pos; i++)
    {
        tmp += _str[i];
    }
    return tmp;
}


2.14 resize()


void resize(size_t n,char ch='0')
{
    if (n < _size)
    {
        _size = n;
        _str[_size] = '\0';
    }
    else
    {
        reserve(n);
        for (size_t i = _size; i < n; i++)
        {
            _str[i] = ch;
        }
        _size = n;
        _str[_size] = '\0';
    }
}


2.15 clear()


void resize(size_t n,char ch='0')
{
    if (n < _size)
    {
        _size = n;
        _str[_size] = '\0';
    }
    else
    {
        reserve(n);
        for (size_t i = _size; i < n; i++)
        {
            _str[i] = ch;
        }
        _size = n;
        _str[_size] = '\0';
    }
}


2.16 clear()


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


2.17 swap()


void swap(mystring& s)
{
    std::swap(_str, s._str);
    std::swap(_size, s._size);
    std::swap(_capacity, s._capacity);
}


2.18 opeartor比较


提供两种写法 :


bool operator<(const mystring s1)const
{
    size_t _i = 0;
    size_t i = 0;
    while (_i < _size && i < s1._size)
    {
        if (_str[_i] < s1._str[i])
        {
            return true;
        }
        else if (_str[_i] > s1._str[i])
        {
            return false;
        }
        else
        {
            _i++, i++;
        }
    }
    if (_i == _size && i != s1._size)
        return true;
    return false;
}


bool operator<(const mystring s1)const
{
    int ret = memcmp(_str, s1._str, _size < s1._size ? _size : s1._size);
  return ret == 0 ? _size < s1._size : ret < 0;
}


之后所有的都可以由这个来改进


bool operator==(const mystring s)const
{
    return _size == s._size && memcmp(_str, s._str, _size) == 0;
}
bool operator<=(const mystring s)const
{
    return (*this < s) || (*this == s);
}
bool operator>=(const mystring s)const
{
    return !(*this < s);
}
bool operator>(const mystring s)const
{
    return !(*this <= s);
}
bool operator!=(const mystring s)const
{
    return !(*this == s);
}


2.19 operator=


mystring& operator=( mystring tmp)
{
    swap(tmp);
    return *this;
}


这里很妙,先是调用拷贝构造,构造一个tmp对象.之后直接交换即可


2.20 operator<<


ostream& operator<<(ostream& out,const H::mystring& s)
{
  out << s.c_str();
  return out;
}


2.21 operator>>


istream& operator>>(istream& in, H::mystring& s)
{
  s.clear();
  char ch = in.get();
  //处理buff之前的缓冲区
  while (ch == ' ' || ch == '\n')
  {
    ch = in.get();
  }
  char buff[128];
  int b = 0;
  while (ch != ' ' && ch != '\n')
  {
    buff[b++] = ch;
    if (b == 127) 
    {
      buff[b] = '\0';
      s += buff;
      b = 0;
    }
    ch = in.get();
  }
  if (b != 0)
  {
    buff[b] = '\0';
    s += buff;
  }
  return in;
}


目录
相关文章
|
8月前
|
Java 开发者
重学Java基础篇—Java类加载顺序深度解析
本文全面解析Java类的生命周期与加载顺序,涵盖从加载到卸载的七个阶段,并深入探讨初始化阶段的执行规则。通过单类、继承体系的实例分析,明确静态与实例初始化的顺序。同时,列举六种触发初始化的场景及特殊场景处理(如接口初始化)。提供类加载完整流程图与记忆口诀,助于理解复杂初始化逻辑。此外,针对空指针异常等问题提出排查方案,并给出最佳实践建议,帮助开发者优化程序设计、定位BUG及理解框架机制。最后扩展讲解类加载器层次与双亲委派机制,为深入研究奠定基础。
263 0
|
5月前
|
对象存储 C++ 容器
c++的string一键介绍
这篇文章旨在帮助读者回忆如何使用string,并提醒注意事项。它不是一篇详细的功能介绍,而是一篇润色文章。先展示重载函数,如果该函数一笔不可带过,就先展示英文原档(附带翻译),最后展示代码实现与举例可以直接去看英文文档,也可以看本篇文章,但是更建议去看英文原档。那么废话少说直接开始进行挨个介绍。
94 3
|
5月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
117 0
|
5月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
197 0
|
7月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
248 12
|
8月前
|
存储 监控 安全
重学Java基础篇—类的生命周期深度解析
本文全面解析了Java类的生命周期,涵盖加载、验证、准备、解析、初始化、使用及卸载七个关键阶段。通过分阶段执行机制详解(如加载阶段的触发条件与技术实现),结合方法调用机制、内存回收保护等使用阶段特性,以及卸载条件和特殊场景处理,帮助开发者深入理解JVM运作原理。同时,文章探讨了性能优化建议、典型异常处理及新一代JVM特性(如元空间与模块化系统)。总结中强调安全优先、延迟加载与动态扩展的设计思想,并提供开发建议与进阶方向,助力解决性能调优、内存泄漏排查及框架设计等问题。
313 5
|
8月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
8月前
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
|
8月前
|
安全 IDE Java
重学Java基础篇—Java Object类常用方法深度解析
Java中,Object类作为所有类的超类,提供了多个核心方法以支持对象的基本行为。其中,`toString()`用于对象的字符串表示,重写时应包含关键信息;`equals()`与`hashCode()`需成对重写,确保对象等价判断的一致性;`getClass()`用于运行时类型识别;`clone()`实现对象复制,需区分浅拷贝与深拷贝;`wait()/notify()`支持线程协作。此外,`finalize()`已过时,建议使用更安全的资源管理方式。合理运用这些方法,并遵循最佳实践,可提升代码质量与健壮性。
224 1
|
8月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!

推荐镜像

更多
  • DNS