5月26日每日学习
文章目录
- string的实现
- 0.类中的private
- 1.头文件定义函数导致的多文件重复定义问题
- 2.构造函数
-
- 2.1带参构造函数的坑点
- 2.2默认构造函数
- [2.3合一 ------上面两个构造函数](#2.3合一 ——上面两个构造函数)
- 3.析构函数
- 4.size
- [5.operator ](#5.operator[ ])
string的实现
0.类中的private
cpp
namespace lcj
{
class string
{
public:
private:
size_t _capacity;
char* _str;
size_t _size;
};
}
1.头文件定义函数导致的多文件重复定义问题
是啥:
函数定义只能出现一次。那么,如果我把++用来测试的函数++ 定义 放在 .h文件中,
------> 两个.c文件都有这个头文件,非法
原因:编译链接的过程 :
- 预处理 :把
#include的头文件内容原封不动地复制 到每个.cpp文件里。- 编译 :分别把
a.cpp和b.cpp编译成 目标文件a.obj/a.o和b.obj/b.o。
此时a.obj里记录了"我定义了sayHello",b.obj里也记录了"我定义了sayHello"。- 链接 :把多个目标文件合并 成一个可执行文件。
链接器看到a.obj和b.obj都定义了一个叫sayHello的函数 ,按照 C++ 的单一定义规则(ODR, One Definition Rule) ,这是非法的,于是报错
解决方法
静态成员函数
唯一区别:没有this指针
限制:
- ++不能访问普通成员变量和成员函数++(因为没有this指针)
- 只能访问静态(static)变量和函数
使用上:
普通成员函数(唯一使用方法 ):
a1.GetCount();( 有this指针)静态成员函数(成员变量也可以):
直接用:
A::GetCount();(✅ 推荐,更方便)(成员变量也可以)先创建类对象再用:
A a1;
a1.GetCount();(没有this指针,但能找到类域)⬇️静态成员变量,所有同类对对象共享------>用来计数
- 最标准的方法:声明和定义分离
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 是随机数
为什么不建议在初始化列表中定义:
- 上面说的,
_str(new char[_size + 1])中的:_size可能因为声明顺序的原因,是随机数 - 即使改变了声明顺序,但,如果有人改了代码,就完了
正确的方式
------>建议在函数体内直接定义:
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
➡️运算符重载的知识在这里⬅️
- 作用:能直接通过下标访问string中的字符
- 返回值:对应字符的引用
两个函数
char& operator[] (size_t pos);const char& operator[] (size_t pos) const;
const char& operator[](size_t pos) const为啥末尾有const❓- 允许 const 对象调用 :如果一个
string对象被声明为const,那么它只能调用那些被const修饰的成员函数。没有末尾const的operator[]版本无法被const对象使用。
- 允许 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];
}