string类从编译链接到构造析构,解决多文件重复定义+运算符重载,面试必考!

5月26日每日学习

文章目录

string的实现

0.类中的private

cpp 复制代码
namespace lcj
{
	class string
	{
	public:


	private:
		size_t _capacity; 
		char* _str;
		size_t _size; 
	};
}

1.头文件定义函数导致的多文件重复定义问题

是啥:

函数定义只能出现一次。那么,如果我把++用来测试的函数++ 定义 放在 .h文件中,

------> 两个.c文件都有这个头文件,非法

原因:编译链接的过程 :

  1. 预处理 :把 #include 的头文件内容原封不动地复制 到每个 .cpp 文件里。
  2. 编译 :分别把 a.cpp 和 b.cpp 编译成 目标文件 a.obj / a.o 和 b.obj / b.o。
    此时 a.obj 里记录了"我定义了 sayHello",b.obj 里也记录了"我定义了 sayHello"。
  3. 链接 :把多个目标文件合并 成一个可执行文件。
    链接器看到 a.obj 和 b.obj 都定义了一个叫 sayHello 的函数 ,按照 C++ 的单一定义规则(ODR, One Definition Rule) ,这是非法的,于是报错

解决方法

  1. 使用inline内联:链接器允许程序中有多个相同的 inline 函数定义,只要它们完全相同。链接器会随便选一个,或者全部丢弃,不会报错。
  2. 静态static成员函数:

静态成员函数

唯一区别:没有this指针

限制:

  • ++不能访问普通成员变量和成员函数++(因为没有this指针)
  • 只能访问静态(static)变量和函数

使用上:

  1. 普通成员函数(唯一使用方法 ):a1.GetCount(); ( 有this指针)

  2. 静态成员函数(成员变量也可以):

    1. 直接用:A::GetCount();(✅ 推荐,更方便)(成员变量也可以)

    2. 先创建类对象再用:

      A a1;

      a1.GetCount(); (没有this指针,但能找到类域)

⬇️静态成员变量,所有同类对对象共享------>用来计数

  1. 最标准的方法:声明和定义分离

MyString.h

cpp 复制代码
#pragma once
#include<iostream>
using namespace std;

namespace lcj
{
	class string
	{
	public: ...... 
	private: ...... 
	};



	void test_string1();
    
    
}

MyString.cpp

cpp 复制代码
#include"MyString.h"
namespace lcj
{
	void test_string1()
	{
		string s1;
		string s2("hello world");
	}
}

test.cpp

cpp 复制代码
#include"MyString.h"

int main() 
{
    lcj::test_string1();
    return 0;
}





2.构造函数

2.1带参构造函数的坑点

❌看似正确:

cpp 复制代码
		string(const char* s)
			:_size(strlen(s))
			, _str(new char[_size + 1])
		{ 
         }


	private:
		size_t _capacity; 
		char* _str;
		size_t _size; 

‼️错误点:初始化列表的 初始化顺序 是 按 声明顺序 ,不是初始化列表顺序‼️

------>_str(new char[_size + 1])中的:_size 是随机数

为什么不建议在初始化列表中定义:

  1. 上面说的,_str(new char[_size + 1])中的:_size 可能因为声明顺序的原因,是随机数
  2. 即使改变了声明顺序,但,如果有人改了代码,就完了

正确的方式

------>建议在函数体内直接定义:

cpp 复制代码
		string(const char* s) 
		{
			_size = strlen(s);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, s );
		}

	private:
		size_t _capacity; 
		char* _str;
		size_t _size; 





2.2默认构造函数

❌看似正确:但是,没法打印------打印时候对空指针解引用

cpp 复制代码
		string()
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{

		}

正确写法:

cpp 复制代码
		string()
			:_str(new char[1]{'\0'})//得写成这样,才能像数组一样操作
			, _size(0)
			, _capacity(0)
		{

		}





2.3合一 ------上面两个构造函数

cpp 复制代码
		string(const char* s = "")//默认有一个'\0'
		{
			_size = strlen(s);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, s);//strcpy也会加上'\0'
		}





3.析构函数

cpp 复制代码
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}





4.size

cpp 复制代码
		size_t size()
		{
			return _size;
		}



5.operator

➡️const修饰类的成员函数的知识在这里⬅️

➡️运算符重载的知识在这里⬅️

  • 作用:能直接通过下标访问string中的字符
  • 返回值:对应字符的引用

两个函数

  1. char& operator[] (size_t pos);
  2. const char& operator[] (size_t pos) const;
  • const char& operator[](size_t pos) const为啥末尾有const❓
    • 允许 const 对象调用 :如果一个 string 对象被声明为 const,那么它只能调用那些被 const 修饰的成员函数。没有末尾 const 的 operator[] 版本无法被 const 对象使用。
cpp 复制代码
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}


		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}
相关推荐
aqiu11111139 分钟前
【C++算法打怪专栏】8. 字符串转换整数 (atoi)
开发语言·c++·算法
爱吃香菜的初学者1 小时前
十四.Linux——消息队列
linux·运维·开发语言
迅猛龙办公室1 小时前
python实现倒序输出数字
开发语言·python
h39746 小时前
DirectShow过滤器开发-视频源过滤器
c++·windows·音视频·directshow
夏幻灵7 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
程序猿编码7 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
西飘客8 小时前
vs 怎么根据dll 生成lib文件
c++·qt
bkspiderx9 小时前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
程序员老陆9 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
沐晓时光9 小时前
C语言入门,深入理解指针(3)
c语言·开发语言