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.cppb.cpp 编译成 目标文件 a.obj / a.ob.obj / b.o
    此时 a.obj 里记录了"我定义了 sayHello",b.obj 里也记录了"我定义了 sayHello"。
  3. 链接 :把多个目标文件合并 成一个可执行文件。
    链接器看到 a.objb.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 修饰的成员函数。没有末尾 constoperator[] 版本无法被 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];
		}
相关推荐
DeepAgent1 小时前
AI Agent 入门指南(05):Agent 循环——观察、思考、行动
面试·agent
风合星语1 小时前
2026 ROS 2 Lyrical C++ 入门(五):Action 实战——任务反馈、取消与超时处理
c++·机器人·ros2·异步编程·lyrical
91刘仁德2 小时前
C++ 继承和多态 设计模式
c语言·c++·笔记
码行山野赴时序归途2 小时前
链表家族收官篇:循环链表
c语言·开发语言·数据结构·链表
顶点多余2 小时前
9.18 面试题总结 --- 绿盟
linux·面试
景熙55232 小时前
单体项目编写思路和落地形式
java·开发语言
库玛西2 小时前
哈夫曼树与前缀编码:数据压缩的贪心核心
c语言·c++·笔记·考研
尾善爱看海2 小时前
《JavaScript 数组操作全攻略:12 类 API + 30 个实战场景 + 20 个避坑指南》
前端·javascript·面试
别动我齐刘海2 小时前
ROS2 Jazzy + C++ 实战路线——进阶学习3
c++·人工智能·vscode·python·算法·机器学习·机器人
0+1113 小时前
算法 --滑动窗口
c++·算法·leetcode