一,重载类对象的toString函数:
#include <iostream>
#include <string.h>
#include <sstream> // std::to_string需要的头文件
using namespace std;
class MyBase {
private:
int age = 10;
std::string tostring; // 必须要全局变量
public:
MyBase() {
cout << "MyBase construct..." << endl;
}
operator const char*() {
tostring = "toString:" + std::to_string(age); // 必须要全局变量
return tostring.c_str();
}
};
int main()
{
MyBase base;
cout << base << endl;
std::string str;
str.append("mytest:");
str.append(base);
cout << str.c_str() << endl;
system("pause");
return 0;
}
如果使用explicit修饰,则不允许隐式调用,必须使用static_cast强制转换:
#include <iostream>
#include <string.h>
#include <sstream>
using namespace std;
class MyBase {
private:
int age = 10;
char* buffer = "abcdefg";
std::string tostring; // 必须要全局变量
public:
MyBase() {
cout << "MyBase construct..." << endl;
}
explicit operator const char*() {
tostring = "toString:" + std::to_string(age); // 必须要全局变量
return tostring.c_str();
}
explicit operator const int() // 将类作为int来使用
{
return age;
}
MyBase operator+(MyBase& add) // 重载+运算符,MyBase base3 = base2 + base1;
{
MyBase newBase;
newBase.age = age + add.age;
return newBase;
}
bool operator==(MyBase& compare) // 重载==运算符
{
if (age == compare.age) {
return true;
}
return false;
}
bool operator!=(MyBase& compare) // 重载==运算符
{
if (age != compare.age) {
return true;
}
return false;
}
bool operator<(const MyBase& compare);
bool operator<=(const MyBase& compare);
bool operator>(const MyBase& compare);
bool operator>=(const MyBase& compare);
MyBase& operator=(const MyBase& compare) // 重载=赋值运算符: MyBase base=base2
{
age = 2 * compare.age;
return *this;
}
void operator()(int newAge) // 重载()函数运算符: MyBase base(2)
{
age = newAge;
}
const char operator[](int index) // 重载[]函数运算符
{
return buffer[index];
}
};
int main()
{
MyBase base;
//cout << base << endl; // error,explicit声明禁止隐式调用
cout << base[3] << endl; // 重载[]函数运算符,向数组一样访问对象中的char*
std::string str = static_cast<const char*>(base);
cout << str.c_str() << endl;
int num = 10 + static_cast<int>(base); // 将类作为int来使用
cout << num << endl;
system("pause");
return 0;
}
不能重载的运算符:
. :成员选择
.* :指针成员选择
''和"" : 作用域
? :三目运算符
sizeof :获取大小
二,重载移动构造函数和移动运算符:
#include <iostream>
#include <string.h>
#include <sstream>
using namespace std;
class MyString {
private:
char* buffer;
MyString() :buffer(NULL) // 私有化默认构造函数
{
cout << "Default constructor called." << " addr:" << hex << this << endl;
}
public:
MyString(const char* initInput) // 构造函数
{
cout << "Constructor called :" << initInput << " addr:" << hex << this << endl;
if (initInput != NULL) {
buffer = new char[strlen(initInput) + 1];
strcpy(buffer, initInput);
}
else {
buffer = NULL;
}
}
/*
MyString(MyString&& moveSrc) // 移动构造函数
{
cout << "Move constructor called :" << moveSrc.buffer << " addr:" << hex << this << endl;
if (moveSrc.buffer != NULL) {
buffer = moveSrc.buffer;
moveSrc.buffer = NULL; // 释放移动源的buffer
}
}
MyString& operator=(MyString&& moveSrc) // 移动运算符
{
cout << "Move assignment op. :" << moveSrc.buffer << " addr:" << hex << this << endl;
if (moveSrc.buffer != NULL && this != &moveSrc) {
delete[] buffer; // 释放自己的buffer
buffer = moveSrc.buffer;
moveSrc.buffer = NULL; // 释放移动源的buffer
}
return *this;
}
*/
MyString(const MyString& copySrc) // 复制构造函数
{
cout << "Copy constructor called :" << copySrc.buffer << " addr:" << hex << this << endl;
if (copySrc.buffer != NULL) {
buffer = new char[strlen(copySrc.buffer) + 1];
strcpy(buffer, copySrc.buffer);
}
else {
buffer = NULL;
}
}
MyString& operator=(const MyString& copySrc) // 赋值运算符
{
cout << "Copy assignment op. :" << copySrc.buffer << " addr:" << hex << this << endl;
if (copySrc.buffer != NULL && this != ©Src) {
if (buffer != NULL) {
delete[] buffer; // 释放自己的buffer
}
buffer = new char[strlen(copySrc.buffer) + 1];
strcpy(buffer, copySrc.buffer);
}
return *this;
}
~MyString() // 析构函数
{
if (buffer != NULL) {
cout << "destructor called :" << buffer << " addr:" << hex << this << endl;
}
else {
cout << "destructor called ." << " addr:" << hex << this << endl;
}
if (buffer != NULL) {
delete[] buffer;
}
}
int GetLength() {
return strlen(buffer);
}
operator const char*() // 重载类的toString
{
return buffer;
}
MyString operator+(const MyString& addThis) // 重载+运算符
{
cout << "operator+ called :" << addThis.buffer << " addr:" << hex << this << endl;
MyString newStr; // 默认构造函数私有化,内部可以调用
if (addThis.buffer != NULL) {
newStr.buffer = new char[GetLength() + strlen(addThis.buffer) + 1];
strcpy(newStr.buffer, buffer);
strcat(newStr.buffer, addThis.buffer);
}
cout << "++++++++++++++++++++++++" << endl;
return newStr;
}
};
void test() {
MyString hello("hello");
MyString world(" world");
MyString cpp(" of C++");
MyString sayHelloAgain("overwrite this.");
sayHelloAgain = hello + world + cpp;
cout << "------------------------" << endl;
}
int main()
{
test();
system("pause");
return 0;
}
在注释重载移动构造函数和重载移动运算符时,执行效果如下:
Constructor called :hello addr:00EFFC84 // 创建hello实例
Constructor called : world addr:00EFFC78 // 创建world实例
Constructor called : of C++ addr:00EFFC6C // 创建cpp实例
Constructor called :overwrite this. addr:00EFFC60 // 创建sayHelloAgain实例
operator+ called : world addr:00EFFC84 // 触发hello实例的operator+
Default constructor called. addr:00EFFB2C // 在hello实例的operator+函数中,创建newStr实例,在类中可以使用私有构造函数
++++++++++++++++++++++++
Copy constructor called :hello world addr:00EFFB94 // 触发'复制构造函数',创建“hello world”实例。
destructor called :hello world addr:00EFFB2C // 释放hello实例的operator+函数中,newStr的析构函数
operator+ called : of C++ addr:00EFFB94 // 触发“hello world”实例的operator+
Default constructor called. addr:00EFFB34 // 在“hello world”实例的operator+函数中,创建newStr实例,在内中可以使用默认构造函数
++++++++++++++++++++++++
Copy constructor called :hello world of C++ addr:00EFFB88 // 触发'复制构造函数',创建“hello world of C++”实例。
destructor called :hello world of C++ addr:00EFFB34 // 释放“hello world”实例的operator+函数中,newStr的析构函数
Copy assignment op. :hello world of C++ addr:00EFFC60 // 触发'赋值运算符',将“hello world of C++”实例赋值给sayHelloAgain
destructor called :hello world of C++ addr:00EFFB88 // 释放“hello world of C++”实例
destructor called :hello world addr:00EFFB94 // 释放“hello world”实例
------------------------
destructor called :hello world of C++ addr:00EFFC60 // 释放sayHelloAgain实例
destructor called : of C++ addr:00EFFC6C // 释放cpp实例
destructor called : world addr:00EFFC78 // 释放world实例
destructor called :hello addr:00EFFC84 // 释放hello实例
请按任意键继续. . .
sayHelloAgain = hello + world + cpp;的过程:
1)在hello的operator+中创建临时newStr实例,并释放newStr;
2)创建“hello+world”实例,使用复制构造函数;
3)在“hello+world”的operator+中创建临时newStr实例,并释放newStr;
4)创建“hello world of C++”实例,使用复制构造函数;
5)将“hello world of C++”实例以operator=赋值给sayHelloAgain实例;如果不重载operator=,则会触发复制构造函数;
6)释放“hello+world”实例和“hello world of C++”实例;
取消注释,使用重载移动构造函数和重载移动运算符:
Constructor called :hello addr:008EF71C // 创建hello实例
Constructor called : world addr:008EF710 // 创建world实例
Constructor called : of C++ addr:008EF704 // 创建cpp实例
Constructor called :overwrite this. addr:008EF6F8 // 创建sayHelloAgain实例
operator+ called : world addr:008EF71C // 触发hello实例的operator+
Default constructor called. addr:008EF5C4 // 在hello实例的operator+函数中,创建newStr实例,在类中可以使用私有构造函数
++++++++++++++++++++++++
Move constructor called :hello world addr:008EF62C // 触发'移动构造函数',创建“hello world”实例。
destructor called . addr:008EF5C4 // 释放hello实例的operator+函数中,newStr的析构函数
operator+ called : of C++ addr:008EF62C // 触发“hello world”实例的operator+
Default constructor called. addr:008EF5CC // 在“hello world”实例的operator+函数中,创建newStr实例,在内中可以使用默认构造函数
++++++++++++++++++++++++
Move constructor called :hello world of C++ addr:008EF620 // 触发'移动构造函数',创建“hello world of C++”实例。
destructor called . addr:008EF5CC // 释放“hello world”实例的operator+函数中,newStr的析构函数
Move assignment op. :hello world of C++ addr:008EF6F8 // 触发'移动运算符',将“hello world of C++”实例赋值给sayHelloAgain
destructor called . addr:008EF620 // 释放“hello world of C++”实例
destructor called :hello world addr:008EF62C // 释放“hello world”实例
------------------------
destructor called :hello world of C++ addr:008EF6F8 // 释放sayHelloAgain实例
destructor called : of C++ addr:008EF704 // 释放cpp实例
destructor called : world addr:008EF710 // 释放world实例
destructor called :hello addr:008EF71C // 释放hello实例
请按任意键继续. . .
编译器实现sayHelloAgain = hello + world + cpp;的过程都是一样的,会创建两个临时实例。
区别在于:“复制构造函数+赋值运算符”中需要通过new新的自由存储空间来实现“深复制”。而“移动构造函数+移动运算符”是通过接管移动源moveSrc中资源的所有权实现的。接下来moveSrc.buffer=NULL,那么在moveStr的析构函数中什么也不做,因为所有权已经移交给目标对象。
总之,移动构造函数避免了不必要的内存分配和复制步骤,从而节省了大量处理时间。
三,自定义字面量
需要定义operator""格式:
ReturnType operator""YourLiteral(ValueType value) {
// 转换代码
}
ValueType只支持以下类型:
unsigned long long int:用于定义整型字面量。
long double:用于定义浮点字面量。
char、wchar_t、char16_t和char32_t:用于定义字符字面量。
const char*:用于定义原始字符串字面量。
const char*和size_t:用于定义字符串字面量。
const wchar_t*和size_t:用于定义字符串字面量。
const char16_t*和size_t:用于定义字符串字面量。
const char32_t*和size_t:用于定义字符串字面量。
#include <iostream>
using namespace std;
struct Temperature
{
double Kelvin; // 开(开尔文温标的计量单位,1开氏度相当于1摄氏度);
Temperature(long double kelvin) :Kelvin(kelvin) {};
};
Temperature operator""_C(long double celcius)
{
// 摄氏度
return Temperature(celcius);
}
Temperature operator""_F(long double dahrenheit)
{
// 华氏温度计的,华氏的(冰点为32度,沸点为212度);
return Temperature((dahrenheit+459.67)*5/9);
}
int main()
{
Temperature t1 = 10.5_C;
Temperature t2 = 10.5_F;
//Temperature t3 = 10_F; // error,因为没有Temperature operator""_F(unsigned long long int)
cout << "t1:" << t1.Kelvin << endl;
cout << "t2:" << t2.Kelvin << endl;
system("pause");
return 0;
}
四,类型转换运算符
1)static_cast,用于转换具备继承关系的对象。向上转换:将子类转换为父类;向下转换:将父类转换为子类。在向下转换时,有可能导致不可预料的调用异常。static_cast只进行编译阶段检查,并不进行运行阶段检查。
Base* objBase = new Base();
Derived* objDer = static_cast<Derived*>(objBase ); // 向下转换,但其实objDer对象中并不具备子类特性
Derived* objDer = new Derived();
Base* objBase = static_cast<Base*>(objDer ); // 向上转换,没有问题
// 隐式向上转换
Derived objDer;
Base* objBase = objDer ;
2)dynamic_cast,用于转换为指定的子类,如果转换不成功,返回NULL。需要对NULL进行判断。dynamic_cast是运行阶段检查。
Base* objBase = new Derived();
Derived* objDer = dynamic_cast<Derived*>(objBase); // objDer不等于NULL
if(objDer!=NULL) {
// do something...
}
假设:Derived1和Derived2都是Base的子类。定义函数:
void mytest(Base* objBase) {
Derived1* objDer = dynamic_cast<Derived1*>(objBase);
if(objDer!=NULL) {
// do something
}
}
那么:
Base* objDer1 = new Derived1();
mytest(objDer1);// dynamic_cast<Derived1*>(objBase)不为NULL
Base* objDer2 = new Derived2();
mytest(objDer2);// dynamic_cast<Derived1*>(objBase)为NULL
一定要对dynamic_cast返回的对象进行NULL判断。
3)reinterpret_cast,无所谓继承关系,强制转换。慎用!
Base* objBase = new Base();
Other* objOther = reinterpret_case<Other*>(objBase );
4)const_cast,为了突破const函数调用限制而存在。
#include <iostream>
#include <string.h>
#include <sstream>
using namespace std;
class MyBase {
private:
public:
void print()
{
cout << "print..." << endl;
}
};
void myTest(const MyBase obj) {
//obj.print(); // 错误,const对象不能访问非const函数
MyBase* newObj = const_cast<MyBase*>(&obj);
newObj->print(); // 可以访问
}
int main()
{
MyBase obj;
myTest(obj);
system("pause");
return 0;
}
五,使用static_assert执行编译阶段检查。
static_assert是C++11新增的功能,可以在不满足指定条件时禁止编译。对模版类来说很有用。
#include <iostream>
#include <string.h>
#include <sstream>
using namespace std;
template <typename T>
class EverythingButInt {
public:
EverythingButInt() {
static_assert(sizeof(T) != sizeof(int), "No int please!"); // 第一个参数为false时触发
}
};
int main()
{
EverythingButInt<int> test; // 编译时报错
system("pause");
return 0;
}
六,assert调试时断言。
包含头文件assert.h。在debug时,如果assert(int expression)中,expression为0。则触发中断。
在release阶段不会触发。也可以在使用#define NDEBUG禁止assert,需要放在#include <assert.h>之前。
#include <iostream>
#include <string.h>
#include <sstream>
// #define NDEBUG
#include <assert.h>
int main()
{
int num = 10;
assert(num < 5);
system("pause");
return 0;
}
使用过多影响性能,一般放在函数开始处,检查参数合法性。
七,使用std::list时,对于自定义类,需要重载operator==才能使用remove(),需要重载operator<才能使用sort():
#include <iostream>
#include <string.h>
#include <list>
using namespace std;
template<typename T>
void displayAsContents(const T& container)
{
for (auto element = container.cbegin(); element != container.cend(); ++element) {
cout << *element << endl;
}
cout << "-----------" << endl;
}
struct ContactItem
{
string name;
string phone;
string displayAs;
ContactItem(const string& conName, const string& conPhone) :name(conName), phone(conPhone), displayAs(conName + ":" + conPhone) { }
bool operator==(const ContactItem& compareItem) const // 被list的remove()调用
{
return (compareItem.name == this->name);
}
bool operator<(const ContactItem& compareItem) const // 被list的sort()调用
{
return (this->name < compareItem.name);
}
operator const char*() const // 被cout使用打印toString
{
return this->displayAs.c_str();
}
};
bool SortByPhone(const ContactItem& item1, const ContactItem& item2)
{
return (item1.phone < item2.phone);
}
int main()
{
list<ContactItem> contacts;
contacts.push_back(ContactItem("Wang", "186"));
contacts.push_back(ContactItem("Adong", "135"));
contacts.push_back(ContactItem("Xiao", "156"));
displayAsContents(contacts);
contacts.sort();
displayAsContents(contacts);
contacts.sort(SortByPhone); // 通过外部的排序二元谓词函数来进行排序
displayAsContents(contacts);
contacts.remove(ContactItem("Adong", "135"));
displayAsContents(contacts);
system("pause");
return 0;
}
八,在std::map或std::multimap中find元素,必须要检查是否到达迭代器末尾:
#include <iostream>
#include <string.h>
#include <map>
using namespace std;
int main()
{
map<string, string> myMap;
//myMap.insert("adong", "test"); // 错误,无法编译,必须要使用pair
myMap.insert(pair<string, string>("adong", "test"));
myMap.insert(pair<string, string>("xiao", "ttt"));
map<string, string>::const_iterator foundPair1 = myMap.find("adong");
if (foundPair1 != myMap.end())
{
cout << foundPair1->first.c_str() << ":" << foundPair1->second.c_str() << endl;
}
map<string, string>::const_iterator foundPair2 = myMap.find("wang");
if (foundPair2 == myMap.end()) // find一定要进行end比对检查
{
//cout << foundPair2->first.c_str() << ":" << foundPair2->second.c_str() << endl;// 运行时会报错
cout << "not found..." << endl;
}
system("pause");
return 0;
}
九、自适应容器
1)std::stack:模拟栈行为的容器,先进后出(LIFO),不允许访问中间元素,头文件<stack>
2)std::queue:模拟队列的容器,先进后出(FIFO);一端进,一端出的队列,不允许访问中间元素,头文件<queue>。注意与std::deque的区别,std::deque两端都可以进出。
3)std::priority_queue:包含最大值(或bool operator=()认为最大的值)的元素位于队首,且只能从队首执行操作。
以上容器不能修改队列中的元素,不能遍历,不能使用STL算法迭代器。
十,STL容器对比
容器 |
优点 |
缺点 |
std::vector(顺序容器) |
只能在末尾插入/删除数据,速度快(时间固定,与容器大小无关);
可以像访问数组一样进行访问;
|
调整大小时将影响性能;
搜索时间随容器包含元素增多而变慢;
insert到任意位置非常耗时;
|
std::deque(顺序容器) |
可以在开头/末尾,插入/删除数据,速度快(时间固定,与容器大小无关);
可以像访问数组一样进行访问;
|
有vector所有缺点;
根据规范,deque不需要支持reserve(),该函数让程序员给vector预留内存空间,以避免重复调整大小,从而提高性能;
|
std::list(顺序容器) |
可以在开头、中间或末尾插入/删除数据,速度快,耗时固定,而vector/deque的insert非常慢;
不论在什么位置插入/删除,指向list中其它元素的迭代器仍有效;
|
不能像数组那样根据索引任意访问元素;
搜索速度比vector慢,由于元素没有存储在连续空间,元素越多,耗时越多。
|
std::forword_list(顺序容器) |
单向链表类,只能沿一个方向遍历; |
只能使用push_front在链表开头插入元素; |
std::set(关联容器) |
搜索时间与元素个数无关,比顺序容器快; |
插入速度比顺序容器慢,因为在插入时要对元素进行排序; |
std::unordered_set(关联容器) |
搜索、插入、删除的速度几乎不受容器包含元素个数的影响; |
由于元素未被严格排序,因此不能依赖元素在容器中的相对位置; |
std::multiset(关联容器) |
用于存储非唯一值的容器; |
插入速度比顺序容器慢,因为在插入时要对元素排序; |
std::unordered_multiset(关联容器) |
用于存储非唯一值的容器;
搜索、插入、删除的速度几乎不受容器包含元素个数的影响;
|
由于元素未被严格排序,因此不能依赖元素在容器中的相对位置; |
std::map(关联容器) |
用于存储键-值对的容器;
搜索速度比顺序容器快;
|
插入时要进行排序,因此插入速度比顺序容器慢; |
std::unordered_map(关联容器) |
搜索、插入、删除元素的耗时固定,不受容器长度影响;
|
元素未被严格排序,不适合元素相对顺序重要的场景;
元素数量少时,可能比map慢;
|
std::multimap(关联容器) |
可以存储键值不唯一的容器; |
插入时排序,插入速度比顺序容器慢。 |
std::unordered_multimap(关联容器) |
可以存储键值不唯一的容器;
搜索、插入、删除元素的耗时固定,不受容器长度影响;
|
元素未被严格排序,不适合元素相对顺序重要的场景;
元素数量少时,可能比multimap慢;
|
分享到:
相关推荐
C++学习笔记C++学习笔记C++学习笔记C++学习笔记C++学习笔记
C++学习笔记
### C++ 学习笔记精华版 #### 一、C++ 语言概述 **1、历史背景** - **C++ 的江湖地位** - Java、C、C++、Python、C# 是当前主流的编程语言之一,而 C++ 在这些语言中以其高效性和灵活性著称。 - **C++ 之父 ...
3. 结构体内存对齐是C++中为了提高内存存取效率而采取的一种内存分配策略。编译器会根据处理器的存取方式和数据类型自动插入填充字节,以确保数据对齐。这可以提高数据存取的效率,但也可能会导致内存的额外消耗。 ...
《千锋C++笔记》是一份综合性的学习资料,涵盖了C++编程语言的基础到高级概念。这份笔记由知名教育机构“千锋”提供,旨在帮助初学者和有一定基础的程序员深入理解和掌握C++这一强大的系统级编程语言。下面将详细...
6. **C++11及以后的新特性**:C++11引入了许多新特性,如auto关键字、右值引用、lambda表达式、智能指针等,C++14和C++17进一步增强了这些特性,使得C++更加现代化和高效。 7. **内存管理**:理解指针是学习C++的...
C++核心学习笔记pdf
- C++支持面向对象编程,类是对象的蓝图,通过封装、继承和多态这三个特性,可以构建复杂的软件系统。这里会讲解如何创建和使用类,以及理解构造函数和析构函数的作用。 5. **内存管理**: - 深入理解动态内存...
这份"C++笔记"包含了学习C++时的重要知识点和实践技巧。 1. **基础语法**:C++的基础包括变量、数据类型(如整型、浮点型、字符型等)、运算符(算术、比较、逻辑、位运算符等)、流程控制语句(如if-else、switch-...
C++Primer中文第三版(C++从入门到精通)第一章的读书笔记,主要是C++程序、预处理器指示符、iostream库等的基础知识点读书笔记。
"自考C++笔记(上)" 本笔记是作者全部手打创作的自考C++笔记,包含课本中例子的详细分析,共47200字,适合没有学过C语言的人认真学习和通过C++自考。 C++程序设计 ### 认识 C++的对象 #### 1.1 初识 ...
这份笔记主要涵盖了C++的基础知识,包括C++11和C++17的新特性,旨在帮助初学者理解C++的核心概念。 ### C++11特性 1. **引用(Reference)**:引用是一种别名机制,一旦引用被初始化为一个对象后,它就始终绑定到...
今天,让我们一起深入探究《黑马C++学习笔记》,这本涵盖了C++编程基础与核心概念的全面教材。 首先,C++的基础知识是每个学习者必须掌握的部分,这包括变量的声明与赋值、输出语句等基本操作。在C++中,变量的声明...
根据给定的信息,我们可以从多个角度来探讨C++的相关知识点,包括但不限于集成开发环境的配置、数据类型初始化、命名空间的使用、类和对象的概念、引用类型的理解、指针的操作、函数重载以及内存管理等方面。...
3. 尽可能使用const:const关键字在C++中的应用非常广泛,它提供了一种向编译器和程序员明确指出哪些数据或函数不应该被修改的方式,帮助减少程序中的错误。 - 指针和const的结合使用:可以用来限制指针本身或者...
C++ 学习笔记C++ 学习笔记C++ 学习笔记C++ 学习笔记002
【C++学习笔记】这份详尽的资源是为那些希望深入了解C++编程语言的人们精心准备的。C++是一种强大的、通用的编程语言,它的设计理念是面向对象,同时支持过程化编程,使得它在系统软件、应用软件、游戏开发、设备...
C++是一种强大的面向对象编程语言,它源自C语言并扩展了其功能,包括类、模板、异常处理等高级特性。以下是对C++基础知识点的详细解释: 1. **空头程序**:C++中的空头程序是一个没有实际操作的简单程序,通常用于...
《Effective Modern C++:改善C++11和C++14的42个具体做法(影印版)(英文版)》中包括以下主题:剖析花括号初始化、noexcept规范、完美转发、智能指针make函数的优缺点;讲解std∷move,std∷forward,rvalue引用和全局...
【达内C++课程笔记】是一份全面涵盖了C++编程语言以及相关技术的教程资源,由达内科技提供。这份笔记不仅包含C++的基础知识,还深入探讨了C++的高级特性和实际应用,旨在帮助学习者从入门到精通,掌握C++编程技能。 ...