C++入门全面指南:从基础到现代C++特性
前言
C++作为一种强大、高效且广泛应用的编程语言,自1979年由Bjarne Stroustrup在贝尔实验室创建以来,已经发展成为软件开发领域的重要基石。它既保留了C语言的高效性和底层控制能力,又引入了面向对象编程、泛型编程等现代编程范式。在当今的软件开发领域,C++广泛应用于操作系统、游戏开发、嵌入式系统、高性能计算、金融交易系统等对性能要求极高的领域。
学习C++不仅能够帮助我们理解计算机系统的底层原理,还能培养严谨的编程思维和高效的问题解决能力。本指南将系统性地介绍C++的核心特性,从基础语法到现代C++11标准的新特性,通过丰富的代码示例和详细解释,帮助读者建立坚实的C++编程基础。
一、C++关键字
C++共有63个关键字,这些关键字是语言的核心组成部分,具有特殊含义,不能作为标识符使用。下面按照功能分类详细介绍主要关键字:
1. 数据类型关键字
// 基本类型bool,char,wchar_t,char16_t,char32_t,char8_t(C++20)short,int,long,longlongfloat,double,longdoublevoid// 类型修饰符signed,unsignedconst,volatile,mutable2. 存储类关键字
auto,register,static,extern,thread_local(C++11)3. 控制流关键字
// 条件控制if,else,switch,case,default// 循环控制for,while,do,break,continue// 跳转goto,return4. 面向对象编程关键字
class,struct,union,enum,enumclass(C++11)public,protected,privatevirtual,override(C++11),final(C++11)this,friend,explicit5. 模板编程关键字
template,typename,class(在模板中)6. 异常处理关键字
try,catch,throw,noexcept(C++11)7. 运算符关键字
new,delete,new[],delete[]sizeof,alignof(C++11)typeid,dynamic_cast,static_cast,const_cast,reinterpret_castoperator8. 其他重要关键字
namespace,using,asmalignas(C++11),alignof(C++11)decltype(C++11),auto(类型推导,C++11)nullptr(C++11),constexpr(C++11)完整的关键字示例:
#include<iostream>#include<typeinfo>// 演示多种关键字的使用classBase{public:virtualvoidprint()const{std::cout<<"Base class"<<std::endl;}virtual~Base()=default;};classDerivedfinal:publicBase{// final关键字防止进一步继承public:voidprint()constoverride{// override确保正确重写虚函数std::cout<<"Derived class"<<std::endl;}};template<typenameT>classTemplateClass{private:T value;public:explicitTemplateClass(T val):value(val){}TgetValue()const{returnvalue;}};intmain(){// auto类型推导autox=10;// x被推导为intautoy=3.14;// y被推导为doubleautoz="hello";// z被推导为const char*// constexpr编译时常量constexprintarray_size=100;intarr[array_size];// nullptr空指针int*ptr=nullptr;// dynamic_cast运行时类型检查Base*basePtr=newDerived();if(Derived*derivedPtr=dynamic_cast<Derived*>(basePtr)){derivedPtr->print();}deletebasePtr;return0;}二、命名空间
命名空间是C++中用于组织代码、防止命名冲突的重要机制。在大型项目中,不同模块可能使用相同的标识符,命名空间可以有效地解决这个问题。
1. 命名空间定义
命名空间可以包含变量、函数、类、模板等任何合法的C++实体。
#include<iostream>#include<string>#include<vector>// 基本命名空间定义namespaceMath{constdoublePI=3.141592653589793;doubleadd(doublea,doubleb){returna+b;}doublemultiply(doublea,doubleb){returna*b;}// 命名空间内可以嵌套类classCalculator{public:staticdoublepower(doublebase,intexponent){doubleresult=1.0;for(inti=0;i<exponent;++i){result*=base;}returnresult;}};}// 命名空间可以分段定义namespaceMath{// 可以继续添加成员doublesubtract(doublea,doubleb){returna-b;}// 嵌套命名空间namespaceConstants{constdoubleE=2.718281828459045;constdoubleGOLDEN_RATIO=1.618033988749895;}}// 匿名命名空间:仅在当前文件内可见namespace{intinternalVariable=42;voidinternalFunction(){std::cout<<"This is an internal function"<<std::endl;}}// 命名空间别名namespaceVeryLongNamespaceName{voidfunction(){std::cout<<"Function in very long namespace"<<std::endl;}}// 创建别名namespaceVLN=VeryLongNamespaceName;// 内联命名空间(C++11)inlinenamespaceVersion1{voidapi(){std::cout<<"Version 1 API"<<std::endl;}}namespaceVersion2{voidapi(){std::cout<<"Version 2 API"<<std::endl;}}// 使用内联命名空间namespaceLibrary{inlinenamespaceCurrent{voidfeature(){std::cout<<"Current feature"<<std::endl;}}namespaceDeprecated{voidfeature(){std::cout<<"Deprecated feature"<<std::endl;}}}2. 命名空间的使用
#include<iostream>#include<string>namespaceCompany{namespaceDepartment{namespaceTeam{classEmployee{private:std::string name;intid;public:Employee(std::string n,inti):name(n),id(i){}voiddisplay()const{std::cout<<"Employee: "<<name<<", ID: "<<id<<std::endl;}};}}}// 方法1:使用完全限定名voidmethod1(){Company::Department::Team::Employeeemp1("Alice",1001);emp1.display();}// 方法2:使用using声明voidmethod2(){usingCompany::Department::Team::Employee;Employeeemp2("Bob",1002);emp2.display();}// 方法3:使用using指令voidmethod3(){usingnamespaceCompany::Department::Team;Employeeemp3("Charlie",1003);emp3.display();}// 方法4:使用命名空间别名voidmethod4(){namespaceCDT=Company::Department::Team;CDT::Employeeemp4("David",1004);emp4.display();}// 演示using声明的作用域voiddemonstrateScope(){// 局部using声明{usingstd::cout;usingstd::endl;cout<<"Inside block with using declarations"<<endl;}// cout和endl在这里不可用(除非全局使用)// cout << "This would cause error" << endl;}// 处理命名冲突namespaceGraphics{classPoint{public:intx,y;Point(intx,inty):x(x),y(y){}};}namespacePhysics{classPoint{public:doublex,y,z;Point(doublex,doubley,doublez):x(x),y(y),z(z){}};}voidhandleNamingConflict(){Graphics::PointgPoint(10,20);Physics::PointpPoint(1.0,2.0,3.0);std::cout<<"Graphics Point: ("<<gPoint.x<<", "<<gPoint.y<<")"<<std::endl;std::cout<<"Physics Point: ("<<pPoint.x<<", "<<pPoint.y<<", "<<pPoint.z<<")"<<std::endl;}// 标准库命名空间使用示例voidstdNamespaceExample(){usingstd::cout;usingstd::endl;usingstd::string;usingstd::vector;string name="C++ Programming";vector<int>numbers={1,2,3,4,5};cout<<"String: "<<name<<endl;cout<<"Numbers: ";for(intnum:numbers){cout<<num<<" ";}cout<<endl;}// 内联命名空间使用voidinlineNamespaceExample(){// 可以直接访问内联命名空间的成员Library::feature();// 使用当前版本// 也可以明确指定版本Library::Current::feature();Library::Deprecated::feature();}intmain(){std::cout<<"=== Namespace Usage Examples ==="<<std::endl;method1();method2();method3();method4();demonstrateScope();handleNamingConflict();stdNamespaceExample();inlineNamespaceExample();// 使用Math命名空间std::cout<<"\n=== Math Namespace Examples ==="<<std::endl;std::cout<<"PI: "<<Math::PI<<std::endl;std::cout<<"Add: "<<Math::add(10.5,20.3)<<std::endl;std::cout<<"Euler's number: "<<Math::Constants::E<<std::endl;std::cout<<"Power: "<<Math::Calculator::power(2,8)<<std::endl;return0;}三、C++输入&输出
C++使用流(stream)进行输入输出操作,这是一种更安全、更灵活的方式,相比于C语言的printf/scanf,C++的I/O支持类型安全、可扩展性更好。
基础输入输出
#include<iostream>// 包含标准输入输出流#include<iomanip>// 包含I/O操作符#include<string>#include<limits>voidbasicIO(){// 标准输出std::cout<<"Hello, World!"<<std::endl;// 输出多个值intage=25;doublesalary=75000.50;std::string name="John Doe";std::cout<<"Name: "<<name<<", Age: "<<age<<", Salary: "<<salary<<std::endl;// 标准输入intnumber;std::cout<<"Enter an integer: ";std::cin>>number;std::cout<<"You entered: "<<number<<std::endl;// 输入多个值inta,b;std::cout<<"Enter two integers: ";std::cin>>a>>b;std::cout<<"Sum: "<<a+b<<std::endl;}// 格式化输出voidformattedOutput(){// 设置宽度和对齐std::cout<<std::setw(15)<<std::left<<"Name"<<std::setw(10)<<std::right<<"Age"<<std::setw(15)<<std::right<<"Salary"<<std::endl;std::cout<<std::setw(15)<<std::left<<"Alice"<<std::setw(10)<<std::right<<30<<std::setw(15)<<std::right<<std::fixed<<std::setprecision(2)<<85000.00<<std::endl;// 数字格式化doublepi=3.141592653589793;std::cout<<"\nDifferent formats of pi:"<<std::endl;std::cout<<"Default: "<<pi<<std::endl;std::cout<<"Fixed (2 decimal): "<<std::fixed<<std::setprecision(2)<<pi<<std::endl;std::cout<<"Scientific: "<<std::scientific<<pi<<std::endl;// 重置格式std::cout.unsetf(std::ios::fixed|std::ios::scientific);std::cout<<std::setprecision(6);// 恢复默认精度// 布尔值格式化boolflag=true;std::cout<<"\nBool as integer: "<<flag<<std::endl;std::cout<<std::boolalpha<<"Bool as text: "<<flag<<std::noboolalpha<<std::endl;}// 字符串输入处理voidstringInput(){std::string fullName;// 清除输入缓冲区std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');std::cout<<"\nEnter your full name: ";std::getline(std::cin,fullName);// 读取整行std::cout<<"Hello, "<<fullName<<"!"<<std::endl;// 逐个单词读取std::cout<<"Enter three words: ";std::string word1,word2,word3;std::cin>>word1>>word2>>word3;std::cout<<"Words: "<<word1<<", "<<word2<<", "<<word3<<std::endl;}// 文件流状态检查voidstreamState(){intvalue;std::cout<<"\nEnter an integer (enter 'abc' to test error handling): ";std::cin>>value;// 检查输入状态if(std::cin.fail()){std::cout<<"Invalid input! Clearing error state..."<<std::endl;std::cin.clear();// 清除错误状态std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');// 忽略错误输入}else{std::cout<<"Valid input: "<<value<<std::endl;}}// 自定义类型的输入输出classPerson{private:std::string name;intage;public:Person(std::string n="",inta=0):name(n),age(a){}// 重载输出运算符friendstd::ostream&operator<<(std::ostream&os,constPerson&p){os<<"Person{name='"<<p.name<<"', age="<<p.age<<"}";returnos;}// 重载输入运算符friendstd::istream&operator>>(std::istream&is,Person&p){std::cout<<"Enter name: ";is>>p.name;std::cout<<"Enter age: ";is>>p.age;returnis;}};voidcustomTypeIO(){Personp1("Alice",30);Person p2;std::cout<<"\n=== Custom Type I/O ==="<<std::endl;std::cout<<"Person 1: "<<p1<<std::endl;std::cout<<"\nEnter details for Person 2:"<<std::endl;std::cin>>p2;std::cout<<"Person 2: "<<p2<<std::endl;}// 二进制输入输出(简单示例)voidbinaryIOExample(){// 注意:这里仅展示概念,实际文件操作需要包含<fstream>intnumbers[]={1,2,3,4,5};std::cout<<"\n=== Binary Representation ==="<<std::endl;// 以十六进制显示内存表示unsignedchar*bytes=reinterpret_cast<unsignedchar*>(numbers);for(inti=0;i<sizeof(numbers);i++){std::cout<<std::hex<<std::setw(2)<<std::setfill('0')<<static_cast<int>(bytes[i])<<" ";if((i+1)%4==0)std::cout<<" ";}std::cout<<std::dec<<std::endl;}intmain(){std::cout<<"=== C++ Input/Output Examples ==="<<std::endl;basicIO();formattedOutput();stringInput();streamState();customTypeIO();binaryIOExample();return0;}高级I/O特性
#include<iostream>#include<iomanip>#include<sstream>// 字符串流#include<fstream>// 文件流#include<vector>// 字符串流示例voidstringStreamDemo(){std::cout<<"\n=== String Stream Demo ==="<<std::endl;// 将数据写入字符串流std::ostringstream oss;oss<<"PI = "<<3.14159<<", E = "<<2.71828;std::string result=oss.str();std::cout<<"Output string: "<<result<<std::endl;// 从字符串读取数据std::string data="100 3.14 Hello";std::istringstreamiss(data);intnum;doublevalue;std::string text;iss>>num>>value>>text;std::cout<<"Parsed: "<<num<<", "<<value<<", "<<text<<std::endl;// 更复杂的解析std::string csv="John,Doe,30,Engineer";std::replace(csv.begin(),csv.end(),',',' ');std::istringstreamcsvStream(csv);std::string firstName,lastName,job;intage;csvStream>>firstName>>lastName>>age>>job;std::cout<<"CSV Parsed: "<<firstName<<" "<<lastName<<", "<<age<<", "<<job<<std::endl;}// 文件流示例voidfileStreamDemo(){std::cout<<"\n=== File Stream Demo ==="<<std::endl;// 写入文件std::ofstreamoutFile("example.txt");if(outFile.is_open()){outFile<<"Hello, File!\n";outFile<<"This is line 2\n";outFile<<"Value: "<<42<<"\n";outFile.close();std::cout<<"File written successfully."<<std::endl;}else{std::cerr<<"Failed to open file for writing."<<std::endl;}// 读取文件std::ifstreaminFile("example.txt");if(inFile.is_open()){std::string line;std::cout<<"\nFile contents:"<<std::endl;while(std::getline(inFile,line)){std::cout<<line<<std::endl;}inFile.close();}// 二进制文件操作std::vector<int>data={1,2,3,4,5};// 写入二进制文件std::ofstreambinOut("data.bin",std::ios::binary);if(binOut.is_open()){binOut.write(reinterpret_cast<char*>(data.data()),data.size()*sizeof(int));binOut.close();}// 读取二进制文件std::ifstreambinIn("data.bin",std::ios::binary);if(binIn.is_open()){binIn.seekg(0,std::ios::end);size_t fileSize=binIn.tellg();binIn.seekg(0,std::ios::beg);std::vector<int>readData(fileSize/sizeof(int));binIn.read(reinterpret_cast<char*>(readData.data()),fileSize);binIn.close();std::cout<<"\nBinary data read: ";for(intval:readData){std::cout<<val<<" ";}std::cout<<std::endl;}}// 流缓冲区操作voidstreamBufferDemo(){std::cout<<"\n=== Stream Buffer Demo ==="<<std::endl;// 重定向cout到stringstreamstd::ostringstream buffer;std::streambuf*oldCoutBuffer=std::cout.rdbuf(buffer.rdbuf());std::cout<<"This goes to the buffer, not the screen!";std::cout<<" More text in buffer.";// 恢复coutstd::cout.rdbuf(oldCoutBuffer);std::cout<<"Buffer contains: "<<buffer.str()<<std::endl;// 使用stringstream作为格式化工具std::stringstream ss;ss<<std::hex<<std::uppercase<<std::setfill('0');intnum=255;ss<<"0x"<<std::setw(8)<<num;std::cout<<"Formatted hex: "<<ss.str()<<std::endl;}// 自定义流操作符std::ostream&customManipulator(std::ostream&os){os<<std::setw(20)<<std::setfill('*');returnos;}voidcustomManipulatorDemo(){std::cout<<"\n=== Custom Manipulator Demo ==="<<std::endl;std::cout<<customManipulator<<"Hello"<<std::endl;std::cout<<customManipulator<<"World"<<std::endl;}// 错误处理示例voiderrorHandlingDemo(){std::cout<<"\n=== Error Handling Demo ==="<<std::endl;std::ifstreamfile("nonexistent.txt");if(!file){std::cerr<<"Error: Could not open file!"<<std::endl;perror("Detailed error");// C风格的错误信息}// 设置异常抛出std::ifstream file2;file2.exceptions(std::ifstream::failbit|std::ifstream::badbit);try{file2.open("nonexistent.txt");}catch(conststd::ifstream::failure&e){std::cerr<<"Exception caught: "<<e.what()<<std::endl;}}intmain(){stringStreamDemo();fileStreamDemo();streamBufferDemo();customManipulatorDemo();errorHandlingDemo();return0;}四、缺省参数
缺省参数是C++中一个非常实用的特性,它允许在函数声明时为参数指定默认值。当调用函数时,如果没有提供该参数的值,就会使用默认值。
1. 缺省参数概念
#include<iostream>#include<string>// 基本缺省参数示例voidprintMessage(conststd::string&message="Hello, World!",intrepeat=1){for(inti=0;i<repeat;++i){std::cout<<message<<std::endl;}}// 带有复杂默认值的函数std::stringcreateGreeting(conststd::string&name="Guest",conststd::string&prefix="Hello",conststd::string&suffix="!"){returnprefix+" "+name+suffix;}// 默认参数可以是表达式intgetDefaultValue(){return42;}voidfunctionWithExpression(intx=getDefaultValue(),doubley=3.14*2){std::cout<<"x = "<<x<<", y = "<<y<<std::endl;}2. 缺省参数分类
#include<iostream>#include<vector>#include<cmath>// 1. 全缺省参数 - 所有参数都有默认值voiddrawRectangle(intwidth=10,intheight=5,charborder='*',charfill=' '){for(inti=0;i<height;++i){for(intj=0;j<width;++j){if(i==0||i==height-1||j==0||j==width-1){std::cout<<border;}else{std::cout<<fill;}}std::cout<<std::endl;}}// 2. 半缺省参数 - 部分参数有默认值// 注意:半缺省参数必须从右向左连续doublecalculatePayment(doubleprincipal,doublerate,// 必须提供intyears=1,// 可选intperiodsPerYear=12){// 可选doubler=rate/periodsPerYear;intn=years*periodsPerYear;returnprincipal*r*pow(1+r,n)/(pow(1+r,n)-1);}// 3. 带有复杂默认值的半缺省参数voidlogMessage(conststd::string&message,conststd::string&level="INFO",std::ostream&output=std::cout,booltimestamp=true){if(timestamp){// 这里可以添加时间戳逻辑output<<"[TIMESTAMP] ";}output<<"["<<level<<"] "<<message<<std::endl;}// 4. 类成员函数中的缺省参数classConfiguration{private:inttimeout;intretries;boolverbose;public:// 构造函数使用缺省参数Configuration(intt=30,intr=3,boolv=false):timeout(t),retries(r),verbose(v){}// 成员函数使用缺省参数voidsetSettings(intt=30,intr=3,boolv=false){timeout=t;retries=r;verbose=v;}voiddisplay()const{std::cout<<"Timeout: "<<timeout<<", Retries: "<<retries<<", Verbose: "<<(verbose?"true":"false")<<std::endl;}};// 5. 模板函数中的缺省参数template<typenameT=int,typenameU=double>classPair{private:T first;U second;public:Pair(T f=T{},U s=U{}):first(f),second(s){}voiddisplay()const{std::cout<<"("<<first<<", "<<second<<")"<<std::endl;}};// 6. 继承中的缺省参数classBase{public:virtualvoiddisplay(intx=10){std::cout<<"Base: "<<x<<std::endl;}};classDerived:publicBase{public:// 注意:重写函数不会继承默认参数!voiddisplay(intx=20)override{std::cout<<"Derived: "<<x<<std::endl;}};// 7. 函数指针中的缺省参数typedefvoid(*PrintFunc)(conststd::string&,int);voiddemonstrateFunctionPointer(){PrintFunc func=printMessage;func("Hello via function pointer",2);}// 8. 缺省参数的常见陷阱voidtrickyExample(intx,inty=x){// 错误!不能使用参数作为默认值// 正确的做法:// void trickyExample(int x, int y = 0)}// 9. 使用constexpr作为默认参数constexprintgetDefaultSize(){return100;}classArrayWrapper{private:int*data;intsize;public:// 使用constexpr函数作为默认参数ArrayWrapper(intsz=getDefaultSize()):size(sz){data=newint[size]{};}~ArrayWrapper(){delete[]data;}};// 10. 可变参数模板与缺省参数结合template<typename...Args>voidlogWithDefaults(conststd::string&message,Args&&...args){// 这里可以处理可变参数std::cout<<message;((std::cout<<" "<<std::forward<Args>(args)),...);std::cout<<std::endl;}// 测试函数voidtestDefaultParameters(){std::cout<<"=== Testing Default Parameters ==="<<std::endl;// 全缺省参数测试std::cout<<"\n1. Drawing rectangles with defaults:"<<std::endl;drawRectangle();// 使用所有默认值std::cout<<"\nCustom rectangle:"<<std::endl;drawRectangle(15,8,'#','.');// 提供所有参数// 半缺省参数测试std::cout<<"\n2. Loan calculations:"<<std::endl;std::cout<<"Monthly payment: $"<<calculatePayment(100000,0.05)<<std::endl;// 1年,12期std::cout<<"Monthly payment: $"<<calculatePayment(100000,0.05,30)<<std::endl;// 30年// 类成员函数测试std::cout<<"\n3. Configuration class:"<<std::endl;Configuration config1;// 使用所有默认值Configurationconfig2(60,5,true);// 提供所有值config1.display();config2.display();// 模板类测试std::cout<<"\n4. Template class with defaults:"<<std::endl;Pair<>p1;// 使用默认类型int, doublePair<std::string>p2("Hello",3.14);// 指定第一个类型p1.display();p2.display();// 继承中的缺省参数问题std::cout<<"\n5. Inheritance and default parameters:"<<std::endl;Base*base=newDerived();base->display();// 输出什么?答案是:Derived: 10deletebase;// 函数指针测试std::cout<<"\n6. Function pointers:"<<std::endl;demonstrateFunctionPointer();// 日志函数测试std::cout<<"\n7. Logging with defaults:"<<std::endl;logMessage("Application started");logMessage("Error occurred","ERROR",std::cerr,false);}// 实际应用示例:配置系统classDatabaseConfig{private:std::string host;intport;std::string username;std::string password;inttimeout;booluseSSL;public:DatabaseConfig(conststd::string&h="localhost",intp=5432,conststd::string&u="admin",conststd::string&pw="",intt=30,boolssl=true):host(h),port(p),username(u),password(pw),timeout(t),useSSL(ssl){}voiddisplay()const{std::cout<<"Database Config:"<<std::endl<<" Host: "<<host<<std::endl<<" Port: "<<port<<std::endl<<" Username: "<<username<<std::endl<<" Timeout: "<<timeout<<"s"<<std::endl<<" SSL: "<<(useSSL?"Enabled":"Disabled")<<std::endl;}};intmain(){testDefaultParameters();std::cout<<"\n=== Real-world Example: Database Config ==="<<std::endl;DatabaseConfig defaultConfig;DatabaseConfigcustomConfig("db.example.com",3306,"root","secret123",60,false);defaultConfig.display();std::cout<<std::endl;customConfig.display();return0;}五、函数重载
函数重载是C++的重要特性之一,它允许在同一作用域内定义多个同名函数,只要它们的参数列表不同。
1. 函数重载概念
#include<iostream>#include<string>#include<vector>#include<cmath>// 基本函数重载示例classMathOperations{public:// 1. 参数类型不同的重载intadd(inta,intb){std::cout<<"Adding integers: ";returna+b;}doubleadd(doublea,doubleb){std::cout<<"Adding doubles: ";returna+b;}// 2. 参数数量不同的重载intadd(inta,intb,intc){std::cout<<"Adding three integers: ";returna+b+c;}// 3. 参数顺序不同的重载(需要不同类型)voidprint(inta,doubleb){std::cout<<"int: "<<a<<", double: "<<b<<std::endl;}voidprint(doublea,intb){std::cout<<"double: "<<a<<", int: "<<b<<std::endl;}// 4. const重载voidprocess(std::string&str){std::cout<<"Processing mutable string: "<<str<<std::endl;str+=" (modified)";}voidprocess(conststd::string&str){std::cout<<"Processing const string: "<<str<<std::endl;}// 5. 指针和引用重载voiddisplay(int*ptr){std::cout<<"Pointer to int: "<<*ptr<<std::endl;}voiddisplay(int&ref){std::cout<<"Reference to int: "<<ref<<std::endl;}// 6. 带默认参数的重载voidcalculate(inta,intb=10){std::cout<<"Calculate with default: "<<a+b<<std::endl;}voidcalculate(inta){std::cout<<"Calculate single: "<<a<<std::endl;}};// 运算符重载(特殊形式的函数重载)classComplex{private:doublereal;doubleimag;public:Complex(doubler=0,doublei=0):real(r),imag(i){}// 运算符重载Complexoperator+(constComplex&other)const{returnComplex(real+other.real,imag+other.imag);}Complexoperator-(constComplex&other)const{returnComplex(real-other.real,imag-other.imag);}// 友元函数形式的运算符重载friendstd::ostream&operator<<(std::ostream&os,constComplex&c);// 前缀++重载Complex&operator++(){++real;++imag;return*this;}// 后缀++重载Complexoperator++(int){Complex temp=*this;++(*this);returntemp;}};std::ostream&operator<<(std::ostream&os,constComplex&c){os<<c.real<<" + "<<c.imag<<"i";returnos;}// 模板函数重载template<typenameT>Tmaximum(T a,T b){std::cout<<"Template max for two values: ";return(a>b)?a:b;}template<typenameT>Tmaximum(T a,T b,T c){std::cout<<"Template max for three values: ";returnmaximum(maximum(a,b),c);}// 重载解析示例voidoverloadResolutionDemo(){MathOperations math;std::cout<<"=== Overload Resolution Examples ==="<<std::endl;// 1. 精确匹配std::cout<<math.add(10,20)<<std::endl;// 调用int版本std::cout<<math.add(10.5,20.3)<<std::endl;// 调用double版本// 2. 类型转换匹配std::cout<<math.add(10,20.5)<<std::endl;// 调用哪个?double版本// 3. 参数数量匹配std::cout<<math.add(1,2,3)<<std::endl;// 4. const重载std::string str="Hello";conststd::string constStr="World";math.process(str);// 调用非常量版本math.process(constStr);// 调用常量版本// 5. 指针和引用重载intvalue=42;int*ptr=&value;math.display(ptr);// 调用指针版本math.display(value);// 调用引用版本// 6. 默认参数带来的歧义// math.calculate(5); // 错误!ambiguous callmath.calculate(5,10);// OKstd::cout<<"\n=== Operator Overloading ==="<<std::endl;Complexc1(3,4);Complexc2(1,2);Complex c3=c1+c2;std::cout<<c1<<" + "<<c2<<" = "<<c3<<std::endl;std::cout<<"\n=== Template Function Overloading ==="<<std::endl;std::cout<<maximum(10,20)<<std::endl;std::cout<<maximum(10,20,15)<<std::endl;std::cout<<maximum(3.14,2.71)<<std::endl;}// 重载函数的最佳实践classStringUtils{public:// 避免过度重载staticstd::stringtrim(conststd::string&str){returntrim(str," \t\n\r");}staticstd::stringtrim(conststd::string&str,conststd::string&delimiters){size_t first=str.find_first_not_of(delimiters);if(first==std::string::npos)return"";size_t last=str.find_last_not_of(delimiters);returnstr.substr(first,last-first+1);}// 使用重载提供便捷接口staticvoidlog(conststd::string&message){log(message,"INFO",std::cout);}staticvoidlog(conststd::string&message,conststd::string&level){log(message,level,std::cout);}staticvoidlog(conststd::string&message,conststd::string&level,std::ostream&output){output<<"["<<level<<"] "<<message<<std::endl;}};// 重载与继承classBaseLogger{public:virtualvoidlog(conststd::string&message){std::cout<<"Base: "<<message<<std::endl;}// 重载函数virtualvoidlog(conststd::string&message,intseverity){std::cout<<"Base["<<severity<<"]: "<<message<<std::endl;}};classFileLogger:publicBaseLogger{public:// 只重写一个版本voidlog(conststd::string&message)override{std::cout<<"File: "<<message<<std::endl;}// 另一个版本仍然可用(继承自基类)};// 测试继承中的重载voidtestInheritanceOverloading(){FileLogger logger;logger.log("Simple message");// 调用派生类版本logger.log("Important",1);// 调用基类版本BaseLogger*basePtr=&logger;basePtr->log("Polymorphic");// 多态调用派生类版本basePtr->log("Polymorphic",2);// 调用基类版本}intmain(){overloadResolutionDemo();std::cout<<"\n=== String Utils Examples ==="<<std::endl;std::string testStr=" Hello World ";std::cout<<"Trimmed: '"<<StringUtils::trim(testStr)<<"'"<<std::endl;StringUtils::log("Application started");StringUtils::log("Error occurred","ERROR");std::cout<<"\n=== Inheritance and Overloading ==="<<std::endl;testInheritanceOverloading();return0;}2. C++支持函数重载的原理——名字修饰
#include<iostream>#include<string>// 名字修饰(Name Mangling)演示// C++编译器会对函数名进行修饰,以支持函数重载// 使用extern "C"禁用名字修饰extern"C"{// C风格函数,没有名字修饰voidc_style_function(intx){std::cout<<"C style function: "<<x<<std::endl;}// C语言不支持函数重载,所以不能这样定义:// void c_style_function(double x); // 错误!}// C++风格函数,支持重载voidcpp_style_function(intx){std::cout<<"C++ int function: "<<x<<std::endl;}voidcpp_style_function(doublex){std::cout<<"C++ double function: "<<x<<std::endl;}voidcpp_style_function(intx,doubley){std::cout<<"C++ int, double function: "<<x<<", "<<y<<std::endl;}// 查看名字修饰// 编译时可以使用 nm 命令查看符号表:// nm ./executable | grep function// 演示不同编译器可能的不同名字修饰classDemoClass{public:voidmember_function(){}voidmember_function(int){}staticvoidstatic_function(){}virtualvoidvirtual_function(){}};// 模板函数的名字修饰template<typenameT>voidtemplate_function(T value){std::cout<<"Template: "<<value<<std::endl;}// 特化版本template<>voidtemplate_function<int>(intvalue){std::cout<<"Specialized for int: "<<value<<std::endl;}// 演示名字空间对名字修饰的影响namespaceOuter{namespaceInner{voidnested_function(){}}}// 演示extern "C"的实际应用// 在C++中调用C库函数extern"C"{// 假设这是C库中的函数声明intc_library_function(constchar*str);}// 创建可以从C调用的C++函数extern"C"{intcpp_function_callable_from_c(intx,inty){returnx+y;}}// 名字修饰的实际影响voiddemonstrateNameMangling(){std::cout<<"=== Name Mangling Demonstration ==="<<std::endl;// 调用C风格函数(没有重载)c_style_function(10);// 调用C++风格函数(支持重载)cpp_style_function(10);cpp_style_function(3.14);cpp_style_function(10,3.14);// 调用模板函数template_function(10);template_function(3.14);template_function("Hello");// 调用命名空间中的函数Outer::Inner::nested_function();// 演示调用约定DemoClass obj;obj.member_function();obj.member_function(10);DemoClass::static_function();// 虚函数调用obj.virtual_function();}// 使用工具分析名字修饰voidanalyzeNameMangling(){std::cout<<"\n=== Name Mangling Analysis ==="<<std::endl;// 在不同编译器下,修饰后的名字可能不同:// GCC/Clang: _Z10some_functioni// MSVC: ?some_function@@YAXH@Z// 可以这样查看:// 1. 编译时添加 -S 生成汇编代码// 2. 使用 nm 命令查看符号表// 3. 使用 c++filt 工具反修饰名字std::cout<<"To see mangled names, compile with:"<<std::endl;std::cout<<" g++ -S source.cpp # Generate assembly"<<std::endl;std::cout<<" nm executable # Show symbols"<<std::endl;std::cout<<" c++filt <symbol> # Demangle names"<<std::endl;}// 跨语言调用的实际例子// 假设有一个C库,我们需要在C++中使用#ifdef__cplusplusextern"C"{#endif// C库的头文件应该这样包装typedefstruct{intx;inty;}Point;voidc_draw_point(Point p);voidc_draw_line(Point p1,Point p2);#ifdef__cplusplus}#endif// C++包装器classGraphicsWrapper{public:staticvoiddrawPoint(intx,inty){Point p={x,y};c_draw_point(p);}staticvoiddrawLine(intx1,inty1,intx2,inty2){Point p1={x1,y1};Point p2={x2,y2};c_draw_line(p1,p2);}};// 演示C调用C++函数// C++端定义extern"C"{voidcpp_callback(intvalue){std::cout<<"C++ callback: "<<value<<std::endl;}}// 模拟C端调用extern"C"{voidc_function_that_calls_cpp(void(*callback)(int)){callback(42);}}intmain(){demonstrateNameMangling();analyzeNameMangling();std::cout<<"\n=== Cross-language Calling ==="<<std::endl;// 模拟C调用C++回调函数c_function_that_calls_cpp(cpp_callback);// 使用C++包装器调用C函数GraphicsWrapper::drawPoint(10,20);GraphicsWrapper::drawLine(0,0,100,100);return0;}六、引用
引用是C++中一个强大而独特的特性,它为变量创建别名,提供了更安全和直观的操作方式。
1. 引用概念
#include<iostream>#include<string>#include<vector>// 基本引用示例voidbasicReferences(){std::cout<<"=== Basic References ==="<<std::endl;intoriginal=42;int&ref=original;// ref是original的引用(别名)std::cout<<"original: "<<original<<std::endl;std::cout<<"ref: "<<ref<<std::endl;std::cout<<"&original: "<<&original<<std::endl;std::cout<<"&ref: "<<&ref<<std::endl;// 地址相同// 通过引用修改值ref=100;std::cout<<"After modification:"<<std::endl;std::cout<<"original: "<<original<<std::endl;// 也变成100std::cout<<"ref: "<<ref<<std::endl;// 引用必须在声明时初始化// int& invalidRef; // 错误:必须初始化}// 引用作为函数参数voidswap(int&a,int&b){inttemp=a;a=b;b=temp;}voidmodifyString(std::string&str){str+=" (modified)";}// 返回引用int&getElement(std::vector<int>&vec,size_t index){if(index<vec.size()){returnvec[index];}throwstd::out_of_range("Index out of range");}// 常量引用voidprintVector(conststd::vector<int>&vec){std::cout<<"Vector elements: ";for(constint&num:vec){// 使用常量引用避免拷贝std::cout<<num<<" ";}std::cout<<std::endl;}2. 引用特性
#include<iostream>#include<string>// 1. 引用必须在定义时初始化voidreferenceInitialization(){std::cout<<"\n=== Reference Initialization ==="<<std::endl;intx=10;// 正确:定义时初始化int&ref1=x;// 错误:未初始化// int& ref2;// 引用不能重新绑定inty=20;// ref1 = y; // 这不是重新绑定,而是赋值std::cout<<"x: "<<x<<", ref1: "<<ref1<<std::endl;ref1=y;// 这会将x的值改为20std::cout<<"After ref1 = y:"<<std::endl;std::cout<<"x: "<<x<<", y: "<<y<<", ref1: "<<ref1<<std::endl;}// 2. 引用类型必须匹配voidreferenceTypeMatching(){std::cout<<"\n=== Reference Type Matching ==="<<std::endl;inti=10;constintci=20;int&ri=i;// OK// int& rci = ci; // 错误:不能将非常量引用绑定到常量constint&rci2=ci;// OK:常量引用绑定到常量constint&rci3=i;// OK:常量引用可以绑定到非常量// 临时对象的引用constint&tempRef=42;// OK:常量引用可以绑定到临时对象// int& tempRef2 = 42; // 错误:非常量引用不能绑定到临时对象}// 3. 引用与指针的区别voidreferenceVsPointer(){std::cout<<"\n=== Reference vs Pointer ==="<<std::endl;intvalue=100;int*ptr=&value;// 指针需要取地址int&ref=value;// 引用直接初始化std::cout<<"value: "<<value<<std::endl;std::cout<<"ptr: "<<ptr<<", *ptr: "<<*ptr<<std::endl;std::cout<<"ref: "<<ref<<std::endl;// 修改值*ptr=200;std::cout<<"After *ptr = 200:"<<std::endl;std::cout<<"value: "<<value<<", ref: "<<ref<<std::endl;ref=300;std::cout<<"After ref = 300:"<<std::endl;std::cout<<"value: "<<value<<", *ptr: "<<*ptr<<std::endl;// 指针可以改变指向,引用不能intanother=500;ptr=&another;// OK// ref = another; // 错误:不能重新绑定,这是赋值}// 4. 引用数组和数组引用voidarrayReferences(){std::cout<<"\n=== Array References ==="<<std::endl;intarr[5]={1,2,3,4,5};// 数组的引用int(&arrRef)[5]=arr;// arrRef是数组的引用std::cout<<"Array elements via reference: ";for(inti=0;i<5;++i){std::cout<<arrRef[i]<<" ";}std::cout<<std::endl;// 不能创建引用数组(数组元素不能是引用)// int& refArr[5]; // 错误}// 5. 引用在范围for循环中的应用voidrangeForWithReferences(){std::cout<<"\n=== Range-based for with References ==="<<std::endl;std::vector<int>numbers={1,2,3,4,5};std::cout<<"Original: ";for(constauto&num:numbers){std::cout<<num<<" ";}std::cout<<std::endl;// 使用引用修改元素std::cout<<"Modifying elements: ";for(auto&num:numbers){num*=2;std::cout<<num<<" ";}std::cout<<std::endl;std::cout<<"After modification: ";for(constauto&num:numbers){std::cout<<num<<" ";}std::cout<<std::endl;}// 6. 引用在类成员函数中的应用classBigData{private:std::vector<int>data;public:BigData(){// 创建大量数据for(inti=0;i<1000;++i){data.push_back(i);}}// 返回常量引用,避免拷贝conststd::vector<int>&getData()const{returndata;}// 返回引用,允许修改std::vector<int>&getMutableData(){returndata;}};voidclassMemberReferences(){std::cout<<"\n=== Class Member References ==="<<std::endl;BigData bigData;// 获取常量引用,只读访问conststd::vector<int>&constData=bigData.getData();std::cout<<"Data size: "<<constData.size()<<std::endl;// 获取非常量引用,可以修改std::vector<int>&mutableData=bigData.getMutableData();mutableData.push_back(1000);std::cout<<"New data size: "<<mutableData.size()<<std::endl;}// 7. 右值引用(C++11)voidrvalueReferences(){std::cout<<"\n=== Rvalue References (C++11) ==="<<std::endl;intx=10;// 左值引用int&lref=x;// 绑定到左值// 右值引用int&&rref=20;// 绑定到右值(临时对象)std::cout<<"x: "<<x<<std::endl;std::cout<<"lref: "<<lref<<std::endl;std::cout<<"rref: "<<rref<<std::endl;// 移动语义示例std::vector<int>source={1,2,3,4,5};std::cout<<"Source size before move: "<<source.size()<<std::endl;// 使用移动语义std::vector<int>destination=std::move(source);std::cout<<"Source size after move: "<<source.size()<<std::endl;std::cout<<"Destination size: "<<destination.size()<<std::endl;}// 8. 引用折叠和完美转发template<typenameT>voidforwardExample(T&&arg){// 引用折叠规则:// T& && -> T&// T&& & -> T&// T& & -> T&// T&& && -> T&&process(std::forward<T>(arg));}voidprocess(int&x){std::cout<<"process(lvalue): "<<x<<std::endl;}voidprocess(int&&x){std::cout<<"process(rvalue): "<<x<<std::endl;}voidtestPerfectForwarding(){std::cout<<"\n=== Perfect Forwarding ==="<<std::endl;intx=10;forwardExample(x);// 调用process(int&)forwardExample(20);// 调用process(int&&)}// 9. 引用在函数式编程中的应用voidfunctionalProgrammingWithReferences(){std::cout<<"\n=== Functional Programming with References ==="<<std::endl;autoadder=[](int&total,intvalue){total+=value;returntotal;};intsum=0;std::vector<int>numbers={1,2,3,4,5};for(intnum:numbers){adder(sum,num);}std::cout<<"Sum: "<<sum<<std::endl;// 使用std::accumulatesum=0;for(constint&num:numbers){sum+=num;}std::cout<<"Sum (manual): "<<sum<<std::endl;}// 10. 引用陷阱和最佳实践voidreferencePitfalls(){std::cout<<"\n=== Reference Pitfalls ==="<<std::endl;// 陷阱1:返回局部变量的引用/* int& badReference() { int local = 42; return local; // 错误:返回局部变量的引用 } */// 陷阱2:悬垂引用int*ptr=newint(100);int&ref=*ptr;deleteptr;// ref现在指向已释放的内存!// 最佳实践:使用常量引用作为函数参数autogoodPractice=[](conststd::string&str){// 安全:不会意外修改输入returnstr.length();};std::string test="Hello";std::cout<<"Length: "<<goodPractice(test)<<std::endl;}intmain(){basicReferences();referenceInitialization();referenceTypeMatching();referenceVsPointer();arrayReferences();rangeForWithReferences();classMemberReferences();rvalueReferences();testPerfectForwarding();functionalProgrammingWithReferences();referencePitfalls();// 演示swap函数std::cout<<"\n=== Swap Function Demo ==="<<std::endl;inta=10,b=20;std::cout<<"Before swap: a="<<a<<", b="<<b<<std::endl;swap(a,b);std::cout<<"After swap: a="<<a<<", b="<<b<<std::endl;return0;}七、内联函数
内联函数是C++中用于提高程序性能的重要特性,它可以减少函数调用的开销。
1. 概念
#include<iostream>#include<chrono>#include<vector>// 基本内联函数示例inlineintsquare(intx){returnx*x;}// 类内的内联函数classMathUtils{public:// 隐式内联:在类定义内实现的成员函数intcube(intx){returnx*x*x;}// 显式内联inlinedoublereciprocal(doublex){return1.0/x;}// 类外定义的内联函数doublepower(doublebase,intexponent);};// 类外定义内联函数inlinedoubleMathUtils::power(doublebase,intexponent){doubleresult=1.0;for(inti=0;i<exponent;++i){result*=base;}returnresult;}// 模板函数通常是内联的template<typenameT>inlineTmax(T a,T b){return(a>b)?a:b;}// 递归函数通常不应该内联(但编译器可能会优化)inlineintfactorial(intn){return(n<=1)?1:n*factorial(n-1);}// 性能测试:比较内联和非内联函数classPerformanceTest{public:// 非内联函数intnonInlineAdd(inta,intb){returna+b;}// 内联函数inlineintinlineAdd(inta,intb){returna+b;}// 测试性能voidrunTest(){constintiterations=100000000;intresult=0;autostart=std::chrono::high_resolution_clock::now();for(inti=0;i<iterations;++i){result+=nonInlineAdd(i,i+1);}autoend=std::chrono::high_resolution_clock::now();autoduration1=std::chrono::duration_cast<std::chrono::milliseconds>(end-start);start=std::chrono::high_resolution_clock::now();for(inti=0;i<iterations;++i){result+=inlineAdd(i,i+1);}end=std::chrono::high_resolution_clock::now();autoduration2=std::chrono::duration_cast<std::chrono::milliseconds>(end-start);std::cout<<"Non-inline function time: "<<duration1.count()<<"ms"<<std::endl;std::cout<<"Inline function time: "<<duration2.count()<<"ms"<<std::endl;std::cout<<"Difference: "<<duration1.count()-duration2.count()<<"ms"<<std::endl;}};// 内联函数的最佳实践classVector2D{private:doublex,y;public:Vector2D(doublex=0,doubley=0):x(x),y(y){}// 简单的getter/setter适合内联inlinedoublegetX()const{returnx;}inlinedoublegetY()const{returny;}inlinevoidsetX(doublenewX){x=newX;}inlinevoidsetY(doublenewY){y=newY;}// 简单的运算适合内联inlinedoublemagnitude()const{returnsqrt(x*x+y*y);}// 复杂的函数不适合内联Vector2Dnormalize()const;};// 复杂函数在类外定义(不内联)Vector2DVector2D::normalize()const{doublemag=magnitude();if(mag==0)returnVector2D();returnVector2D(x/mag,y/mag);}// 内联函数的限制voidinlineLimitations(){std::cout<<"=== Inline Function Limitations ==="<<std::endl;// 内联函数不能有循环或递归(但某些编译器可能会处理)// 内联只是建议,编译器可能忽略// 获取函数地址int(*funcPtr)(int)=square;std::cout<<"Address of square function: "<<(void*)funcPtr<<std::endl;std::cout<<"square(5) = "<<funcPtr(5)<<std::endl;}// 现代C++中的constexpr函数constexprintconstexprSquare(intx){returnx*x;}// constexpr函数在编译时计算voidconstexprDemo(){std::cout<<"\n=== Constexpr Functions ==="<<std::endl;// 编译时计算constexprintsize=constexprSquare(10);intarray[size];// 使用编译时常量作为数组大小std::cout<<"Compile-time square of 10: "<<size<<std::endl;// 运行时也可以使用intx=5;intresult=constexprSquare(x);std::cout<<"Runtime square of 5: "<<result<<std::endl;}// 内联变量(C++17)inlineconstexprdoublePI=3.141592653589793;// 内联命名空间变量namespaceConstants{inlineconstexprdoubleGRAVITY=9.8;inlineconstexprdoubleLIGHT_SPEED=299792458.0;}// 测试内联函数voidtestInlineFunctions(){std::cout<<"=== Inline Function Testing ==="<<std::endl;MathUtils math;// 测试各种内联函数std::cout<<"square(5) = "<<square(5)<<std::endl;std::cout<<"math.cube(3) = "<<math.cube(3)<<std::endl;std::cout<<"math.reciprocal(4) = "<<math.reciprocal(4)<<std::endl;std::cout<<"math.power(2, 8) = "<<math.power(2,8)<<std::endl;// 测试模板内联函数std::cout<<"max(10, 20) = "<<max(10,20)<<std::endl;std::cout<<"max(3.14, 2.71) = "<<max(3.14,2.71)<<std::endl;// 测试递归内联函数std::cout<<"factorial(5) = "<<factorial(5)<<std::endl;// 测试内联变量std::cout<<"\nInline variables:"<<std::endl;std::cout<<"PI = "<<PI<<std::endl;std::cout<<"Gravity = "<<Constants::GRAVITY<<std::endl;}// 实际应用:几何计算库classGeometry{public:// 内联的几何计算函数staticinlinedoublecircleArea(doubleradius){returnPI*radius*radius;}staticinlinedoublecircleCircumference(doubleradius){return2*PI*radius;}staticinlinedoubletriangleArea(doublebase,doubleheight){return0.5*base*height;}staticinlinedoubledistance(doublex1,doubley1,doublex2,doubley2){doubledx=x2-x1;doubledy=y2-y1;returnsqrt(dx*dx+dy*dy);}};intmain(){testInlineFunctions();inlineLimitations();constexprDemo();// 性能测试std::cout<<"\n=== Performance Test ==="<<std::endl;PerformanceTest test;test.runTest();// 几何计算示例std::cout<<"\n=== Geometry Calculations ==="<<std::endl;std::cout<<"Circle area (r=5): "<<Geometry::circleArea(5)<<std::endl;std::cout<<"Circle circumference (r=5): "<<Geometry::circleCircumference(5)<<std::endl;std::cout<<"Triangle area (b=10, h=5): "<<Geometry::triangleArea(10,5)<<std::endl;std::cout<<"Distance (0,0) to (3,4): "<<Geometry::distance(0,0,3,4)<<std::endl;return0;}八、auto关键字(C++11)
auto关键字是C++11引入的一个重要特性,它实现了类型自动推导,让代码更简洁易读。
#include<iostream>#include<vector>#include<map>#include<string>#include<typeinfo>#include<memory>#include<functional>// 1. 基本auto用法voidbasicAutoUsage(){std::cout<<"=== Basic auto Usage ==="<<std::endl;// 基本类型推导autox=10;// intautoy=3.14;// doubleautoz="Hello";// const char*autoflag=true;// boolstd::cout<<"x type: "<<typeid(x).name()<<", value: "<<x<<std::endl;std::cout<<"y type: "<<typeid(y).name()<<", value: "<<y<<std::endl;std::cout<<"z type: "<<typeid(z).name()<<", value: "<<z<<std::endl;std::cout<<"flag type: "<<typeid(flag).name()<<", value: "<<flag<<std::endl;// 带修饰符的autoconstautocx=100;// const intauto&rx=x;// int&constauto&crx=x;// const int&auto&&urx=x;// int& (左值引用)auto&&urv=42;// int&& (右值引用)// 数组推导intarr[]={1,2,3,4,5};autoarrAuto=arr;// int* (数组退化为指针)auto&arrRef=arr;// int(&)[5] (数组引用)std::cout<<"arr size via auto: "<<sizeof(arr)<<std::endl;// 20std::cout<<"arrAuto size: "<<sizeof(arrAuto)<<std::endl;// 8 (指针大小)std::cout<<"arrRef size: "<<sizeof(arrRef)<<std::endl;// 20}// 2. auto与容器迭代器voidautoWithContainers(){std::cout<<"\n=== auto with Containers ==="<<std::endl;std::vector<int>numbers={1,2,3,4,5};std::map<std::string,int>scores={{"Alice",90},{"Bob",85},{"Charlie",92}};// 传统迭代器写法for(std::vector<int>::iterator it=numbers.begin();it!=numbers.end();++it){std::cout<<*it<<" ";}std::cout<<std::endl;// 使用auto简化for(autoit=numbers.begin();it!=numbers.end();++it){std::cout<<*it<<" ";}std::cout<<std::endl;// 遍历mapfor(autoit=scores.begin();it!=scores.end();++it){std::cout<<it->first<<": "<<it->second<<std::endl;}// 更简洁的范围for循环(配合auto)for(constauto&num:numbers){std::cout<<num<<" ";}std::cout<<std::endl;for(constauto&[name,score]:scores){// C++17结构化绑定std::cout<<name<<": "<<score<<std::endl;}}// 3. auto与函数返回值// C++14开始支持函数返回类型推导autoadd(inta,intb)->int{// 尾随返回类型returna+b;}// C++14: 自动推导返回类型automultiply(inta,intb){returna*b;}// 推导复杂类型autocreateVector(){returnstd::vector<int>{1,2,3,4,5};}// decltype(auto): 保持引用和const性质intglobal=42;constint&getGlobal(){returnglobal;}voidreturnTypeDeduction(){std::cout<<"\n=== Return Type Deduction ==="<<std::endl;autoresult1=add(10,20);autoresult2=multiply(10,20);autovec=createVector();std::cout<<"add(10, 20) = "<<result1<<std::endl;std::cout<<"multiply(10, 20) = "<<result2<<std::endl;std::cout<<"Vector size: "<<vec.size()<<std::endl;// decltype(auto)示例autox=getGlobal();// int (去掉引用和const)decltype(auto)y=getGlobal();// const int& (保持原样)std::cout<<"auto x type: "<<typeid(x).name()<<std::endl;std::cout<<"decltype(auto) y type: "<<typeid(y).name()<<std::endl;}// 4. auto与lambda表达式voidautoWithLambdas(){std::cout<<"\n=== auto with Lambdas ==="<<std::endl;// 传统lambda存储方式std::function<int(int,int)>func1=[](inta,intb){returna+b;};// 使用auto简化autofunc2=[](inta,intb){returna+b;};// 自动推导参数类型 (C++14)autofunc3=[](autoa,autob){returna+b;};// 泛型lambda (C++20概念)autofunc4=[]<typenameT>(T a,T b){returna+b;};std::cout<<"func1(10, 20) = "<<func1(10,20)<<std::endl;std::cout<<"func2(10, 20) = "<<func2(10,20)<<std::endl;std::cout<<"func3(10, 20) = "<<func3(10,20)<<std::endl;std::cout<<"func3(3.14, 2.71) = "<<func3(3.14,2.71)<<std::endl;std::cout<<"func4(10, 20) = "<<func4(10,20)<<std::endl;}// 5. auto与模板编程template<typenameContainer>voidprocessContainer(constContainer&container){// 使用auto推导元素类型for(constauto&element:container){std::cout<<element<<" ";}std::cout<<std::endl;}template<typenameT1,typenameT2>autoaddDifferentTypes(T1 a,T2 b)->decltype(a+b){returna+b;}voidautoWithTemplates(){std::cout<<"\n=== auto with Templates ==="<<std::endl;std::vector<int>intVec={1,2,3};std::vector<std::string>strVec={"Hello","World","C++"};processContainer(intVec);processContainer(strVec);autoresult1=addDifferentTypes(10,3.14);// doubleautoresult2=addDifferentTypes(std::string("Hello"),std::string(" World"));// std::stringstd::cout<<"addDifferentTypes(10, 3.14) = "<<result1<<std::endl;std::cout<<"addDifferentTypes(string, string) = "<<result2<<std::endl;}// 6. auto陷阱和注意事项voidautoPitfalls(){std::cout<<"\n=== auto Pitfalls ==="<<std::endl;// 陷阱1:推导出意外类型autox={1,2,3};// std::initializer_list<int>// auto y{1, 2, 3}; // C++17前:initializer_list,C++17:错误// 陷阱2:引用和const丢失constintci=42;autoa=ci;// int (const丢失)auto&b=ci;// const int& (正确)// 陷阱3:auto和代理对象std::vector<bool>boolVec={true,false,true};autoboolVal=boolVec[0];// std::vector<bool>::reference (代理对象)// boolVal可能不是bool类型!// 正确做法:boolboolVal2=boolVec[0];autoboolVal3=static_cast<bool>(boolVec[0]);// 陷阱4:auto影响代码可读性autoresult=someComplexFunction();// 类型不明确// 最佳实践:在复杂情况下明确类型usingComplexType=std::map<std::string,std::vector<std::pair<int,double>>>;ComplexType data=getComplexData();}// 7. auto在并发编程中的应用#include<thread>#include<future>#include<atomic>voidautoInConcurrency(){std::cout<<"\n=== auto in Concurrency ==="<<std::endl;// 自动推导线程autothreadFunc=[](){std::cout<<"Thread running..."<<std::endl;};autot=std::thread(threadFunc);t.join();// 自动推导futureautofuture=std::async([](){return42;});autoresult=future.get();std::cout<<"Async result: "<<result<<std::endl;// 原子变量autoatomicVar=std::atomic<int>{0};atomicVar.store(100);std::cout<<"Atomic value: "<<atomicVar.load()<<std::endl;}// 8. auto与现代C++特性结合#include<optional>#include<variant>#include<any>voidautoWithModernCpp(){std::cout<<"\n=== auto with Modern C++ ==="<<std::endl;// optionalautomaybeValue=std::optional<int>{42};if(maybeValue){std::cout<<"Optional value: "<<*maybeValue<<std::endl;}// variantautovariantValue=std::variant<int,double,std::string>{3.14};std::visit([](auto&&arg){usingT=std::decay_t<decltype(arg)>;ifconstexpr(std::is_same_v<T,int>){std::cout<<"Variant holds int: "<<arg<<std::endl;}elseifconstexpr(std::is_same_v<T,double>){std::cout<<"Variant holds double: "<<arg<<std::endl;}elseifconstexpr(std::is_same_v<T,std::string>){std::cout<<"Variant holds string: "<<arg<<std::endl;}},variantValue);// anyautoanyValue=std::any{std::string("Hello")};try{autostr=std::any_cast<std::string>(anyValue);std::cout<<"Any holds string: "<<str<<std::endl;}catch(conststd::bad_any_cast&e){std::cout<<"Bad any cast: "<<e.what()<<std::endl;}}// 9. 实际应用示例:配置文件解析classConfigParser{public:autoparse(conststd::string&filename){// 模拟解析配置文件std::map<std::string,std::map<std::string,std::variant<int,double,std::string>>>config;config["database"]["host"]="localhost";config["database"]["port"]=5432;config["database"]["timeout"]=30.5;config["server"]["max_connections"]=1000;config["server"]["enable_ssl"]=true;returnconfig;}};voidconfigExample(){std::cout<<"\n=== Config Parser Example ==="<<std::endl;ConfigParser parser;autoconfig=parser.parse("config.ini");// 遍历配置for(constauto&[section,values]:config){std::cout<<"["<<section<<"]"<<std::endl;for(constauto&[key,value]:values){std::cout<<" "<<key<<" = ";std::visit([](auto&&arg){usingT=std::decay_t<decltype(arg)>;ifconstexpr(std::is_same_v<T,int>){std::cout<<arg;}elseifconstexpr(std::is_same_v<T,double>){std::cout<<arg;}elseifconstexpr(std::is_same_v<T,std::string>){std::cout<<"\""<<arg<<"\"";}elseifconstexpr(std::is_same_v<T,bool>){std::cout<<(arg?"true":"false");}},value);std::cout<<std::endl;}}}intmain(){basicAutoUsage();autoWithContainers();returnTypeDeduction();autoWithLambdas();autoWithTemplates();autoPitfalls();autoInConcurrency();autoWithModernCpp();configExample();return0;}九、基于范围的for循环(C++11)
基于范围的for循环是C++11引入的语法糖,它极大地简化了容器遍历的代码。
#include<iostream>#include<vector>#include<map>#include<set>#include<list>#include<array>#include<string>#include<algorithm>#include<ranges>// C++20// 1. 基本用法voidbasicRangeFor(){std::cout<<"=== Basic Range-based for Loop ==="<<std::endl;// 数组遍历intarr[]={1,2,3,4,5};std::cout<<"Array: ";for(intnum:arr){std::cout<<num<<" ";}std::cout<<std::endl;// vector遍历std::vector<int>vec={10,20,30,40,50};std::cout<<"Vector: ";for(intnum:vec){std::cout<<num<<" ";}std::cout<<std::endl;// string遍历std::string str="Hello";std::cout<<"String characters: ";for(charch:str){std::cout<<ch<<" ";}std::cout<<std::endl;}// 2. 使用auto简化voidrangeForWithAuto(){std::cout<<"\n=== Range-for with auto ==="<<std::endl;std::vector<std::string>words={"apple","banana","cherry"};// 值拷贝(可能昂贵)std::cout<<"By value (copy): ";for(autoword:words){std::cout<<word<<" ";}std::cout<<std::endl;// 常量引用(推荐)std::cout<<"By const reference: ";for(constauto&word:words){std::cout<<word<<" ";}std::cout<<std::endl;// 引用(用于修改)std::cout<<"By reference (modifying): ";for(auto&word:words){word[0]=toupper(word[0]);std::cout<<word<<" ";}std::cout<<std::endl;}// 3. 自定义类型支持范围for循环classSimpleRange{private:intstart,end;public:SimpleRange(ints,inte):start(s),end(e){}// 必须提供begin()和end()方法int*begin(){return&start;}constint*begin()const{return&start;}int*end(){return&end+1;}// 注意:这里只是示例,实际实现更复杂constint*end()const{return&end+1;}};voidcustomRangeClass(){std::cout<<"\n=== Custom Range Class ==="<<std::endl;// 注意:这个示例只是为了演示原理// 实际的自定义范围类需要正确实现迭代器SimpleRangerange(1,5);std::cout<<"Custom range: ";for(intnum:range){std::cout<<num<<" ";}std::cout<<std::endl;}// 4. 标准库容器遍历voidstandardContainers(){std::cout<<"\n=== Standard Library Containers ==="<<std::endl;// liststd::list<int>lst={1,2,3,4,5};std::cout<<"List: ";for(constauto&num:lst){std::cout<<num<<" ";}std::cout<<std::endl;// setstd::set<std::string>fruits={"apple","banana","orange"};std::cout<<"Set: ";for(constauto&fruit:fruits){std::cout<<fruit<<" ";}std::cout<<std::endl;// mapstd::map<int,std::string>students={{101,"Alice"},{102,"Bob"},{103,"Charlie"}};std::cout<<"Map (C++17前): ";for(constauto&pair:students){std::cout<<"{"<<pair.first<<": "<<pair.second<<"} ";}std::cout<<std::endl;// C++17结构化绑定std::cout<<"Map (C++17结构化绑定): ";for(constauto&[id,name]:students){std::cout<<"{"<<id<<": "<<name<<"} ";}std::cout<<std::endl;}// 5. 修改元素voidmodifyingElements(){std::cout<<"\n=== Modifying Elements ==="<<std::endl;std::vector<int>numbers={1,2,3,4,5};std::cout<<"Original: ";for(constauto&num:numbers){std::cout<<num<<" ";}std::cout<<std::endl;// 使用引用修改std::cout<<"Squaring elements: ";for(auto&num:numbers){num=num*num;std::cout<<num<<" ";}std::cout<<std::endl;// 再次查看修改结果std::cout<<"After modification: ";for(constauto&num:numbers){std::cout<<num<<" ";}std::cout<<std::endl;}// 6. 遍历多维容器voidmultiDimensional(){std::cout<<"\n=== Multi-dimensional Containers ==="<<std::endl;// 二维vectorstd::vector<std::vector<int>>matrix={{1,2,3},{4,5,6},{7,8,9}};std::cout<<"2D vector:"<<std::endl;for(constauto&row:matrix){for(constauto&element:row){std::cout<<element<<" ";}std::cout<<std::endl;}// 数组的数组intarr2D[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};std::cout<<"\n2D array:"<<std::endl;for(constauto&row:arr2D){for(intelement:row){std::cout<<element<<" ";}std::cout<<std::endl;}}// 7. 使用初始化列表voidwithInitializerList(){std::cout<<"\n=== With Initializer List ==="<<std::endl;// 直接遍历初始化列表std::cout<<"Direct initializer list: ";for(intnum:{1,2,3,4,5}){std::cout<<num<<" ";}std::cout<<std::endl;// 结合算法std::cout<<"With algorithm (squares): ";for(intnum:{1,2,3,4,5}){std::cout<<num*num<<" ";}std::cout<<std::endl;}// 8. 性能考虑#include<chrono>voidperformanceComparison(){std::cout<<"\n=== Performance Comparison ==="<<std::endl;constsize_t size=1000000;std::vector<int>largeVec(size,1);// 传统for循环autostart=std::chrono::high_resolution_clock::now();longlongsum1=0;for(size_t i=0;i<largeVec.size();++i){sum1+=largeVec[i];}autoend=std::chrono::high_resolution_clock::now();autoduration1=std::chrono::duration_cast<std::chrono::microseconds>(end-start);// 范围for循环start=std::chrono::high_resolution_clock::now();longlongsum2=0;for(constauto&num:largeVec){sum2+=num;}end=std::chrono::high_resolution_clock::now();autoduration2=std::chrono::duration_cast<std::chrono::microseconds>(end-start);// 迭代器循环start=std::chrono::high_resolution_clock::now();longlongsum3=0;for(autoit=largeVec.begin();it!=largeVec.end();++it){sum3+=*it;}end=std::chrono::high_resolution_clock::now();autoduration3=std::chrono::duration_cast<std::chrono::microseconds>(end-start);std::cout<<"Traditional for loop: "<<duration1.count()<<" microseconds"<<std::endl;std::cout<<"Range-based for loop: "<<duration2.count()<<" microseconds"<<std::endl;std::cout<<"Iterator loop: "<<duration3.count()<<" microseconds"<<std::endl;std::cout<<"Sums: "<<sum1<<", "<<sum2<<", "<<sum3<<std::endl;}// 9. C++20范围库 (ranges)#ifdef__cpp_lib_rangesvoidcpp20Ranges(){std::cout<<"\n=== C++20 Ranges ==="<<std::endl;std::vector<int>numbers={1,2,3,4,5,6,7,8,9,10};// 使用视图过滤和转换autoevenSquares=numbers|std::views::filter([](intn){returnn%2==0;})|std::views::transform([](intn){returnn*n;});std::cout<<"Even numbers squared: ";for(intnum:evenSquares){std::cout<<num<<" ";}std::cout<<std::endl;// 使用视图取前N个autofirstThree=numbers|std::views::take(3);std::cout<<"First three: ";for(intnum:firstThree){std::cout<<num<<" ";}std::cout<<std::endl;// 反向视图autoreversed=numbers|std::views::reverse;std::cout<<"Reversed: ";for(intnum:reversed){std::cout<<num<<" ";}std::cout<<std::endl;}#endif// 10. 实际应用示例classStudent{private:std::string name;std::vector<int>grades;public:Student(std::string n,std::vector<int>g):name(n),grades(g){}doubleaverageGrade()const{if(grades.empty())return0.0;doublesum=0.0;for(intgrade:grades){sum+=grade;}returnsum/grades.size();}voiddisplay()const{std::cout<<name<<": ";for(intgrade:grades){std::cout<<grade<<" ";}std::cout<<"(Avg: "<<averageGrade()<<")"<<std::endl;}};voidstudentManagement(){std::cout<<"\n=== Student Management Example ==="<<std::endl;std::vector<Student>students={Student("Alice",{90,85,92}),Student("Bob",{78,82,80}),Student("Charlie",{95,96,94})};std::cout<<"Student grades:"<<std::endl;for(constauto&student:students){student.display();}// 计算班级平均分doubleclassAverage=0.0;for(constauto&student:students){classAverage+=student.averageGrade();}classAverage/=students.size();std::cout<<"\nClass average: "<<classAverage<<std::endl;// 找出高于平均分的学生std::cout<<"\nStudents above class average:"<<std::endl;for(constauto&student:students){if(student.averageGrade()>classAverage){std::cout<<student.averageGrade()<<" ";}}std::cout<<std::endl;}// 11. 范围for循环的陷阱voidrangeForPitfalls(){std::cout<<"\n=== Range-for Pitfalls ==="<<std::endl;std::vector<int>numbers={1,2,3,4,5};// 陷阱1:在遍历时修改容器std::cout<<"Bad example (modifying container while iterating):"<<std::endl;// for (auto& num : numbers) {// if (num == 3) {// numbers.push_back(6); // 可能使迭代器失效!// }// std::cout << num << " ";// }// 陷阱2:临时容器的遍历std::cout<<"\nTemporary container example:"<<std::endl;for(intnum:std::vector<int>{1,2,3}){std::cout<<num<<" ";// 临时对象在循环期间有效}std::cout<<std::endl;// 陷阱3:使用auto&&处理代理对象std::vector<bool>boolVec={true,false,true};std::cout<<"\nProxy object example: ";for(auto&&val:boolVec){// 使用auto&&处理代理对象std::cout<<val<<" ";}std::cout<<std::endl;}intmain(){basicRangeFor();rangeForWithAuto();customRangeClass();standardContainers();modifyingElements();multiDimensional();withInitializerList();performanceComparison();#ifdef__cpp_lib_rangescpp20Ranges();#endifstudentManagement();rangeForPitfalls();return0;}十、指针空值nullptr(C++11)
nullptr是C++11引入的空指针常量,解决了传统NULL宏在类型安全和重载解析中的问题。
#include<iostream>#include<type_traits>#include<memory>// 1. nullptr基本用法voidbasicNullptr(){std::cout<<"=== Basic nullptr Usage ==="<<std::endl;// 初始化指针int*ptr1=nullptr;double*ptr2=nullptr;void*ptr3=nullptr;// 检查空指针if(ptr1==nullptr){std::cout<<"ptr1 is nullptr"<<std::endl;}if(!ptr2){// 隐式转换为boolstd::cout<<"ptr2 is also nullptr"<<std::endl;}// 与NULL比较int*ptr4=NULL;// 传统方式(不推荐)if(ptr4==nullptr){std::cout<<"NULL equals nullptr"<<std::endl;}}// 2. nullptr vs NULL vs 0voidcompareWithNull(){std::cout<<"\n=== nullptr vs NULL vs 0 ==="<<std::endl;// NULL通常是0或(void*)0#ifdefNULLstd::cout<<"NULL is defined as: "<<NULL<<std::endl;#endif// 类型信息std::cout<<"Type of nullptr: "<<typeid(nullptr).name()<<std::endl;std::cout<<"Type of NULL: "<<typeid(NULL).name()<<std::endl;std::cout<<"Type of 0: "<<typeid(0).name()<<std::endl;// nullptr的类型是std::nullptr_tstd::nullptr_t null_value=nullptr;std::cout<<"Type of null_value: "<<typeid(null_value).name()<<std::endl;}// 3. 函数重载中的nullptrvoidoverloadedFunction(int*ptr){std::cout<<"Called with pointer: "<<ptr<<std::endl;}voidoverloadedFunction(intnum){std::cout<<"Called with integer: "<<num<<std::endl;}voidoverloadedFunction(std::nullptr_t nullp){std::cout<<"Called with nullptr_t"<<std::endl;}voidtestOverloading(){std::cout<<"\n=== Function Overloading ==="<<std::endl;// 使用nullptr - 明确调用指针版本overloadedFunction(nullptr);// 调用指针版本或nullptr_t版本// 使用0或NULL - 可能调用整数版本overloadedFunction(0);// 调用整数版本overloadedFunction(NULL);// 可能调用整数版本,取决于NULL的定义int*ptr=nullptr;overloadedFunction(ptr);// 调用指针版本}// 4. 模板中的nullptrtemplate<typenameT>voidtemplateFunction(T*ptr){if(ptr==nullptr){std::cout<<"Null pointer in template"<<std::endl;}else{std::cout<<"Valid pointer: "<<*ptr<<std::endl;}}template<typenameT>voidcheckPointer(T ptr){ifconstexpr(std::is_pointer_v<T>){if(ptr==nullptr){std::cout<<"Pointer is null"<<std::endl;}else{std::cout<<"Pointer is valid"<<std::endl;}}else{std::cout<<"Not a pointer type"<<std::endl;}}voidtestWithTemplates(){std::cout<<"\n=== Templates and nullptr ==="<<std::endl;intx=42;int*ptr1=&x;int*ptr2=nullptr;templateFunction(ptr1);templateFunction(ptr2);checkPointer(ptr1);checkPointer(ptr2);checkPointer(nullptr);checkPointer(10);// 不是指针}// 5. 智能指针中的nullptr#include<memory>voidsmartPointersAndNullptr(){std::cout<<"\n=== Smart Pointers and nullptr ==="<<std::endl;// 创建空智能指针std::unique_ptr<int>up1=nullptr;std::shared_ptr<int>sp1=nullptr;std::weak_ptr<int>wp1;// 检查智能指针是否为空if(!up1){std::cout<<"unique_ptr is empty"<<std::endl;}if(sp1==nullptr){std::cout<<"shared_ptr is nullptr"<<std::endl;}// 重置为nullptrautosp2=std::make_shared<int>(42);std::cout<<"sp2 use_count: "<<sp2.use_count()<<std::endl;sp2=nullptr;// 释放资源if(sp2==nullptr){std::cout<<"sp2 reset to nullptr"<<std::endl;}// 使用reset方法autoup2=std::make_unique<int>(100);up2.reset();// 等同于 up2 = nullptrif(!up2){std::cout<<"up2 has been reset"<<std::endl;}}// 6. nullptr在类中的应用classResource{private:int*data;public:Resource():data(nullptr){}// 使用nullptr初始化explicitResource(intvalue){data=newint(value);}~Resource(){deletedata;data=nullptr;// 防止悬垂指针}// 禁用拷贝Resource(constResource&)=delete;Resource&operator=(constResource&)=delete;// 启用移动Resource(Resource&&other)noexcept:data(other.data){other.data=nullptr;}Resource&operator=(Resource&&other)noexcept{if(this!=&other){deletedata;data=other.data;other.data=nullptr;}return*this;}boolisValid()const{returndata!=nullptr;}intgetValue()const{if(data){return*data;}throwstd::runtime_error("Resource is empty");}};voidclassExample(){std::cout<<"\n=== Class Example ==="<<std::endl;Resource res1;// 空资源Resourceres2(42);// 有值资源std::cout<<"res1 is valid: "<<(res1.isValid()?"true":"false")<<std::endl;std::cout<<"res2 is valid: "<<(res2.isValid()?"true":"false")<<std::endl;try{std::cout<<"res2 value: "<<res2.getValue()<<std::endl;// std::cout << "res1 value: " << res1.getValue() << std::endl; // 抛出异常}catch(conststd::exception&e){std::cout<<"Exception: "<<e.what()<<std::endl;}// 移动语义Resource res3=std::move(res2);std::cout<<"After move:"<<std::endl;std::cout<<"res2 is valid: "<<(res2.isValid()?"true":"false")<<std::endl;std::cout<<"res3 is valid: "<<(res3.isValid()?"true":"false")<<std::endl;}// 7. nullptr与类型安全voidtypeSafety(){std::cout<<"\n=== Type Safety ==="<<std::endl;// nullptr是类型安全的int*ip=nullptr;double*dp=nullptr;// 不能将nullptr赋值给非指针类型// int i = nullptr; // 错误// bool b = nullptr; // 错误(C++11中,但在C++中nullptr可以转换为bool false)// 但可以这样:boolb1=(ip==nullptr);// trueboolb2=ip;// false(隐式转换)std::cout<<"b1: "<<b1<<std::endl;std::cout<<"b2: "<<b2<<std::endl;// nullptr与其他指针类型的比较void*vp=nullptr;if(ip==vp){// 可以比较std::cout<<"int* and void* can both be nullptr"<<std::endl;}}// 8. 实际应用:工厂模式classProduct{public:virtual~Product()=default;virtualvoiduse()=0;};classConcreteProductA:publicProduct{public:voiduse()override{std::cout<<"Using Product A"<<std::endl;}};classConcreteProductB:publicProduct{public:voiduse()override{std::cout<<"Using Product B"<<std::endl;}};classFactory{public:staticstd::unique_ptr<Product>createProduct(conststd::string&type){if(type=="A"){returnstd::make_unique<ConcreteProductA>();}elseif(type=="B"){returnstd::make_unique<ConcreteProductB>();}returnnullptr;// 无法创建时返回nullptr}};voidfactoryPatternExample(){std::cout<<"\n=== Factory Pattern Example ==="<<std::endl;autoproduct1=Factory::createProduct("A");autoproduct2=Factory::createProduct("B");autoproduct3=Factory::createProduct("C");// 无效类型if(product1){product1->use();}if(product2){product2->use();}if(!product3){std::cout<<"Failed to create product C"<<std::endl;}}// 9. nullptr与完美转发template<typenameT>voidprocessValue(T&&value){std::cout<<"Processing value..."<<std::endl;}template<typenameT>voidprocessPointer(T*ptr){if(ptr){std::cout<<"Pointer value: "<<*ptr<<std::endl;}else{std::cout<<"Null pointer"<<std::endl;}}voidperfectForwardingExample(){std::cout<<"\n=== Perfect Forwarding with nullptr ==="<<std::endl;intx=42;int*ptr=&x;// 完美转发nullptrprocessValue(nullptr);// T被推导为std::nullptr_t// 转发指针processValue(ptr);// T被推导为int*processValue(nullptr);// T被推导为std::nullptr_t// 明确调用指针版本processPointer(ptr);processPointer(nullptr);}// 10. C++17的optional与nullptr#include<optional>voidoptionalExample(){std::cout<<"\n=== std::optional and nullptr ==="<<std::endl;std::optional<int>maybeInt;std::optional<std::string>maybeString="Hello";// optional没有值时的行为类似nullptrif(!maybeInt){std::cout<<"maybeInt has no value"<<std::endl;}if(maybeString){std::cout<<"maybeString has value: "<<*maybeString<<std::endl;}// 重置optionalmaybeString=std::nullopt;// 类似于 nullptrif(!maybeString){std::cout<<"maybeString is now empty"<<std::endl;}}// 11. 性能考虑voidperformanceConsiderations(){std::cout<<"\n=== Performance Considerations ==="<<std::endl;// nullptr在性能上与NULL/0相同// 主要优势是类型安全,不是性能constintiterations=100000000;autostart=std::chrono::high_resolution_clock::now();for(inti=0;i<iterations;++i){int*p1=nullptr;(void)p1;}autoend=std::chrono::high_resolution_clock::now();autoduration1=std::chrono::duration_cast<std::chrono::milliseconds>(end-start);start=std::chrono::high_resolution_clock::now();for(inti=0;i<iterations;++i){int*p2=NULL;(void)p2;}end=std::chrono::high_resolution_clock::now();autoduration2=std::chrono::duration_cast<std::chrono::milliseconds>(end-start);start=std::chrono::high_resolution_clock::now();for(inti=0;i<iterations;++i){int*p3=0;(void)p3;}end=std::chrono::high_resolution_clock::now();autoduration3=std::chrono::duration_cast<std::chrono::milliseconds>(end-start);std::cout<<"nullptr: "<<duration1.count()<<"ms"<<std::endl;std::cout<<"NULL: "<<duration2.count()<<"ms"<<std::endl;std::cout<<"0: "<<duration3.count()<<"ms"<<std::endl;}// 12. 最佳实践voidbestPractices(){std::cout<<"\n=== Best Practices ==="<<std::endl;// 1. 总是使用nullptr而不是NULL或0int*goodPtr=nullptr;// int* badPtr = NULL; // 避免// int* worsePtr = 0; // 避免// 2. 在检查指针时使用显式比较if(goodPtr==nullptr){// 清晰std::cout<<"Pointer is null"<<std::endl;}if(!goodPtr){// 也可以,但可能不够清晰std::cout<<"Pointer is null (implicit)"<<std::endl;}// 3. 释放后立即设为nullptrint*dynamicPtr=newint(42);deletedynamicPtr;dynamicPtr=nullptr;// 防止悬垂指针// 4. 在函数参数中使用nullptr作为默认值autoconfigure=[](int*option=nullptr){if(option){*option=100;}};// 5. 使用智能指针避免手动nullptr检查autosmartPtr=std::make_unique<int>(42);if(smartPtr){// 仍然可以检查,但不是必须的std::cout<<"Smart pointer has value: "<<*smartPtr<<std::endl;}}intmain(){basicNullptr();compareWithNull();testOverloading();testWithTemplates();smartPointersAndNullptr();classExample();typeSafety();factoryPatternExample();perfectForwardingExample();optionalExample();performanceConsiderations();bestPractices();return0;}总结
通过本文的详细讲解和丰富的代码示例,我们已经系统地学习了C++的入门核心概念和现代特性。让我们回顾一下重点:
核心收获
C++关键字:理解了63个关键字的分类和基本用途,这是掌握C++语法的基础。
命名空间:学会了如何组织代码、避免命名冲突,理解了命名空间的各种用法和最佳实践。
输入输出系统:掌握了C++强大的流式I/O,包括格式化输出、文件操作和字符串流处理。
缺省参数:了解了如何设计灵活的函数接口,通过合理的默认值减少代码重复。
函数重载:掌握了通过参数列表区分同名函数的技巧,理解了名字修饰的实现原理。
引用:深入理解了引用作为别名的本质,掌握了左值引用、右值引用和完美转发。
内联函数:学会了如何通过内联优化小型函数,理解了内联的适用场景和限制。
auto关键字:掌握了类型自动推导,使代码更简洁,配合现代C++特性更加强大。
基于范围的for循环:学会了简化容器遍历的新语法,提高了代码可读性。
nullptr:理解了类型安全的空指针,解决了传统NULL的歧义问题。
现代C++编程建议
拥抱现代特性:尽可能使用C++11及更高版本的特性,它们让代码更安全、高效。
类型安全:优先使用智能指针、引用和nullptr,避免原始指针的滥用。
资源管理:遵循RAII原则,确保资源的正确获取和释放。
代码简洁性:合理使用auto、范围for循环等特性,但不要过度使用影响可读性。
性能意识:理解内联、移动语义等特性对性能的影响,但不要过早优化。
学习路径建议
对于C++初学者,建议按照以下路径继续深入学习:
- 面向对象编程:深入学习类、继承、多态等面向对象特性。
- 模板编程:掌握函数模板和类模板,理解泛型编程。
- 标准库:系统学习STL容器、算法和迭代器。
- 高级主题:研究异常处理、多线程、移动语义等高级特性。
- 现代C++:学习C++14/17/20的新特性,如概念、协程等。
C++是一门博大精深的语言,学习曲线较陡,但掌握它将为你打开系统编程、游戏开发、高性能计算等领域的大门。坚持实践、阅读优秀代码、参与开源项目是提升C++技能的最佳途径。
记住,编程不仅是学习语法,更是培养解决问题和设计系统的能力。C++为你提供了强大的工具,如何使用它们创造价值,取决于你的智慧和努力。祝你在C++的学习之旅中不断进步!