☰
C++设计基础知识点(不包含面向对象)
2026/10/21 11:26:54 网站建设 项目流程

C++基础设计

一、基础程序设计结构

以.cpp作为文件后缀名的源代码文件

#include<iostream>//用于输入输出 using namespace std;//可以省略cout,endl等的前缀 int main(){ cout<<"test.cpp"<<endl; return 0; }

输入:cin

cin >> 变量;

输出:cout

cout << "内容" << 变量 << endl;

二、引用

​ 引用是 C++ 独有的语法,C 语言没有;引用不是新变量,只是已有变量的别名

  1. 语法

    数据类型 &引用名 = 原变量; //示例 int a = 10; int &b = a; // b 是a的引用(别名
    • &这里不是取地址符,是引用声明标记

    • a和b代表同一块内存空间,不是复制一份新数据

      int a = 10; int &b = a; b = 20; cout << a; // 输出 20!修改b,a跟着变

      引用 b 就是 a 的外号,叫 b 和叫 a,都是同一个人。

  2. 使用特点

    • 引用必须初始化;

      #include <iostream> using namespace std; int main() { int a = 10; int &r1 = a; // 定义同时初始化 int &r2; // 编译报错,引用没有初始化 return 0; }
    • 引用的数据类型必须和被引用的变量的数据类型一致;

      int main() { int a = 10; double b = 3.14; int &r1 = a; // 类型匹配 int &r2 = b; // double变量,不能用int引用绑定 return 0; }
    • 不存在多级引用(没有&&引用的引用);

      int main() { int a = 10; int &r = a; int &&rr = r; // 不是多级引用!这里&&是右值引用(C++11新语法,和本基础章节无关) int & &rr = r; // 编译报错,不存在引用的引用(多级引用) return 0; }
    • 不存在引用类型的数组(数组里面存放引用);

      int main() { int a=1,b=2,c=3; int arr1[5] = {a,b,c}; int &arr2[5] = {a,b,c}; // 非法:引用数组,不能创建 int (&ref_arr)[5] = arr1; // ref_arr 是整个arr1数组的引用 return 0; }
    • 普通引用不能引用常量(字面量 / 临时值)

      int main() { int &r = 100; // 普通引用,不能绑定字面常量 const int &cr = 100; // const常引用,可以绑定常量、临时值 return 0; }
  3. 函数参数

    1. 值传递

      ​ 实参拷贝一份副本给形参,形参是独立的新变量,和外面实参互不干扰。 函数内部修改的只是副本,不会影响外部原始实参。

      #include <iostream> using namespace std; void swap(int x, int y) // x,y 是实参的拷贝副本(值传递) { int temp = x; x = y; y = temp; cout << "函数内部 x=" << x << " y=" << y << endl; } int main() { int a = 10, b = 20; swap(a, b); cout << "函数外部 a=" << a << " b=" << b << endl; return 0; } /* 函数内部 x=20 y=10 函数外部 a=10 b=20 */

      特点:副本独立,修改形参,外面不变

      缺点:拷贝数据,数据量大的时候效率低;无法修改外部变量

    2. 地址传递

      ​ 把实参的地址拷贝给指针形参。 形参指针保存实参内存地址,通过解引用*,可以直接操作外部原始变量。

      #include <iostream> using namespace std; void swap(int *x, int *y) // x,y是指针变量,接收实参地址 { int temp = *x; *x = *y; *y = temp; } int main() { int a = 10, b = 20; swap(&a, &b); // 调用时要取地址 &a &b cout << "a=" << a << " b=" << b << endl; return 0; } //a = 20,b = 10

      优点:不拷贝原始数据,可以修改外部变量

      缺点:

      • 调用时需要手动写&取地址
      • 函数内部取值需要写*解引用,写法麻烦
      • 指针存在风险:有可能传入空指针nullptr,程序崩溃
    3. 引用传递

      ​ 形参是实参变量的别名,形参和实参同一块内存,没有拷贝副本。 在函数内部操作形参,等价于直接操作外面原始实参。

      #include <iostream> using namespace std; void swap(int &x, int &y) // &表示引用;x是main中实参a的别名,y是b别名 { int temp = x; x = y; y = temp; } int main() { int a = 10, b = 20; swap(a, b); // 调用直接写变量名!不用写&取地址 cout << "a=" << a << " b=" << b << endl; return 0; } //a = 20;b = 10

      优点

      • 不需要拷贝副本,节省内存,效率高(传递结构体、大数组优势巨大)

      • 可以修改外部实参的值(和指针效果一样)

      • 写法简单:调用时直接传变量,不用&,函数内不用*解引用

      • 不存在空引用,比指针更安全

      底层:引用传递编译器底层还是用指针实现,但是语法层面简化了。

  4. 引用 vs 指针

    特点引用 &指针 *
    本质变量别名,语法糖,没有独立内存独立变量,存地址,占用内存
    初始化定义时必须绑定变量可以先定义,后面赋值,可空
    能否改绑一旦绑定,不能换目标可以随时修改指向别的变量
    使用方式直接写名字,不用解引用*取值需要解引用*p
    地址&引用和原变量地址完全相同指针变量本身有自己独立地址
  5. const 常引用

    ​const关键字修饰引用,常引用可以引用常量,也可以引用变量;如果只读取、不修改实参**,推荐使用const 类型 &**

    1. 常引用独有的特性

      1. 常引用引用变量

        int var = 100; const int &ref1 = var; cout << "var = " << var << ", ref1 = " << ref1 << endl; var = 200; cout << "var = " << var << ", ref1 = " << ref1 << endl; // ref1 = 300; // 错误,不能通过常引用修改变量的值
      2. 常引用引用常量(普通引用不能引用常量)

        // int& ref2 = 10; // 错误,普通引用不能引用常量 const int &ref2 = 10; // 正确,常引用可以引用常量 cout << "ref2 = " << ref2 << endl;
      3. 常引用可以引用不同类型的变量(会进行隐式类型转换,生成临时变量)

        double d = 3.14; // int& ref3 = d; // 错误,类型不匹配 const int &ref3 = d; // 正确,常引用可以引用不同类型(生成临时变量) cout << "d = " << d << ", ref3 = " << ref3 << endl; d = 6.28; cout << "d = " << d << ", ref3 = " << ref3 << endl; // ref3的值没有改变,因为它引用的是临时变量
      4. 常引用作为函数参数(保护实参不被修改,同时支持传递常量)

        void printNum(const int &num) { cout << "printNum: " << num << endl; // num = 456; // 错误,不能修改常引用参数 } int var = 100; void printNum(const int &num); printNum(123); // 可以传递常量 printNum(var); // 可以传递变量布尔类型
    2. 常见坑点

      1. 常引用不能修改引用本身指向的值,但原变量可改

        int a = 10; const int &r = a; a = 20; cout << r; //输出20 // r = 30; // 报错,不能通过r修改
      2. const 常引用绑定其他类型,会产生临时变量,断开联动。一旦发生类型转换,引用绑定的是临时值,不是原变量。

      3. 区分「const 变量」和「const 引用」

        const int a = 10; const int &r = a; // 合法,常引用绑定const变量 int &r2 = a; // 普通引用不能绑定const变量!

        a 是只读常量,如果允许普通引用int&绑定,就可以通过引用修改常量,语法禁止。

三、作用域

  1. 函数原型作用域

    ​变量的作用域范围在函数原型内,即函数声明中变量所在的参数列表内。

    1. 参数名仅在函数声明的参数列表内有效,函数体外部无法访问这些参数名

      int isEqual(int a, int b); // a, b 的作用域仅限于此声明 // 这里不能访问 a 或 b,因为它们属于函数原型作用域 int c = a; c = b;
    2. 函数定义时的参数名可以与声明时不同

      bool isEqual(int x, int y) { // 定义时可以使用不同的参数名 return x == y; }
  2. 局部作用域

    ​变量的作用域范围在函数体内,或者在复合语句(花括号{})内

    1. 内层作用域可以访问外层作用域的变量(由内向外查找)

      void func() { int localVar = 10; // 外层局部变量 cout << "外层 localVar = " << localVar << endl; { cout << "内层 localVar = " << localVar << endl; //10 } }
    2. 外层作用域无法访问内层作用域的变量

      void func() { { int innerVar = 20; // 复合语句内的局部变量 cout << "内层 innerVar = " << innerVar << endl; } // cout << innerVar; // 错误!外层无法访问内层变量 }
    3. 同名变量遵循"就近原则":内层变量会隐藏外层同名变量

      void func() { int localVar = 10; // 外层局部变量 cout << "外层 localVar = " << localVar << endl; { int localVar = 30; // 内层同名变量,隐藏外层变量 cout << "内层 localVar = " << localVar << endl; // 输出30,不是10 } cout << "外层 localVar = " << localVar << endl;// 输出10 }
  3. 全局作用域

    ​全局变量从声明处开始到整个程序结束都能访问。

    1. 所有函数都可以访问全局变量,生命周期贯穿整个程序运行期间(存储在静态存储区)

      int globalVar = 100; // 全局变量,整个程序都能访问 void func1() { cout << "func1: globalVar = " << globalVar << endl; } void func2() { cout << "func2: globalVar = " << globalVar << endl; } int main() { cout << "main: globalVar = " << globalVar << endl; func1(); func2(); cout << "main: globalVar = " << globalVar << endl; return 0; }
    2. 全局变量默认初始化为0

      int globalVar; // 全局变量,整个程序都能访问 void func1() { cout << "func1: globalVar = " << globalVar << endl;//0 } void func2() { globalVar = 200; // 修改全局变量 cout << "func2: globalVar = " << globalVar << endl;//200 } int main() { func1(); func2(); return 0; }
  4. 类作用域

    ​类内部的成员能够访问的区域,被称为类作用域

    1. 类成员(成员变量和成员函数)的作用域在类内部,类外部访问需要通过对象、指针或引用,并使用 . 或 -> 操作符

      class MyClass { private: int privateVar = 100; // 私有成员,类外不可访问 public: int publicVar = 200; // 公共成员,类内外都可访问 void classFunc() { cout << "privateVar = " << privateVar << endl; cout << "publicVar = " << publicVar << endl; } }; int main() { MyClass obj; obj.classFunc(); // 通过对象调用成员函数 // cout << obj.privateVar; // 错误!私有成员类外不可访问 cout << "obj.publicVar = " << obj.publicVar << endl; return 0; }
    2. 类成员函数内部可以直接访问类的所有成员(包括private成员),类的静态成员属于类作用域,不属于对象

      class MyClass { private: int privateVar = 100; // 私有成员,类外不可访问 public: int publicVar = 200; // 公共成员,类内外都可访问 void classFunc() { // 类内部可以直接访问所有成员 cout << "privateVar = " << privateVar << endl; cout << "publicVar = " << publicVar << endl; } };
  5. 命名空间作用域

    ​在指定的命名空间内,进行有效访问的区域。

    **语法** namespace 命名空间名 { // 变量、函数、类等 }
    1. 命名空间用于组织代码,避免命名冲突

      namespace MyNamespace { int namespaceVar = 200; void namespaceFunc() { cout << "命名空间中的函数:namespaceVar = " << namespaceVar << endl; } class MyClass { public: void classFunc() { cout << "class"<< endl; } } } int main() { return 0; }
    2. 命名空间内的成员需要使用 :: 作用域区分符访问

      namespace MyNamespace { int namespaceVar = 200; void namespaceFunc() { cout << "命名空间中的函数:namespaceVar = " << namespaceVar << endl; } } int main() { // 使用作用域区分符访问 cout << "MyNamespace::namespaceVar = " << MyNamespace::namespaceVar << endl; MyNamespace::namespaceFunc(); return 0; }
    3. 可以使用 using namespace 指令简化访问

      namespace MyNamespace { int namespaceVar = 200; void namespaceFunc() { cout << "命名空间中的函数:namespaceVar = " << namespaceVar << endl; } } int main() { // 使用using指令简化 using namespace MyNamespace; cout << "使用using后:namespaceVar = " << namespaceVar << endl; return 0; }
    4. 命名空间可以嵌套

      namespace MyNamespace { // 嵌套命名空间 namespace InnerSpace { int innerVar = 300; } } int main() { // 访问嵌套命名空间 cout << "MyNamespace::InnerSpace::innerVar = " << MyNamespace::InnerSpace::innerVar << endl; return 0; }
    5. 命名空间可以跨文件

四、函数的默认参数

  1. 概念

    ​C++程序允许用户给函数预先设置参数的默认值。如果用户不为该函数传递实际参数,则函数使用参数的默认值;如果用户传递了实际参数,则函数使用实际参数。(默认参数是在编译阶段确定的,编译器会在调用点将缺失的参数替换为默认值。)

  2. 语法

    // 函数声明时设置默认参数 返回值类型 函数名(数据类型 变量名1=值, 数据类型 变量名2=值...); //三个参数(String类型,int类型,String类型) void printInfo(string name = "张三", int age = 18, string gender = "男");
  3. 使用规则

    1. 声明与定义的关系(如果函数声明处添加了参数默认值,则函数定义处可以不加默认值)

      // 声明时设置默认值 void printInfo(string name = "张三", int age = 18, string gender = "男"); // 定义时可以不加默认值 void printInfo(string name, int age, string gender) { cout << "姓名: " << name << endl; cout << "年龄: " << age << endl; cout << "性别: " << gender << endl; } //**注意**:如果函数只有定义没有声明,则默认参数必须在定义处设置: void printInfo(string name = "张三", int age = 18, string gender = "男") { // 函数体 }
    2. 默认参数的顺序(在拥有多个参数的函数使用默认值时,默认值的右边不能有非默认值存在)

      // 正确:默认值都在右边 void func1(int a, int b = 10, int c = 20); // 错误:默认值右边有非默认值 // void func2(int a = 10, int b, int c); // 错误:默认值之间有非默认值 // void func3(int a, int b = 10, int c, int d = 30);
    3. 引用作为函数参数的默认值(普通引用不能绑定到临时对象,因此普通引用参数不能加默认值)

      //普通引用 `int &ref` 必须绑定到一个左值(可修改的变量); //`10` 是一个右值(临时对象),无法绑定到普通引用; //`const int &ref` 可以绑定到右值,因为它承诺不修改引用的对象 // void func1(int &ref = 10);// 错误:普通引用不能绑定到常量10(临时对象) // 正确:const引用可以绑定常量 void func2(const int &ref = 10); // 正确:使用指针代替引用 void func3(int *p = nullptr); // 正确:普通参数可以加默认值 void func4(int num = 10);

五.内联函数

  1. 概念

    ​当一个函数在程序中被频繁大量调用时,可以将这个函数声明为内联函数(Inline Function)。

    **普通函数调用的开销**: 1. 主调函数暂停执行 2. CPU切换到被调函数,开辟函数栈帧(内存) 3. 保存当前执行状态(现场) 4. 重置程序计数器(PC),跳转到被调函数 5. 执行被调函数 6. 被调函数结束后,释放函数栈帧 7. 恢复现场(恢复寄存器、程序计数器等) 8. 继续执行主调函数 **内联函数的优化**: 内联函数在编译之后会将函数体**直接嵌入**到函数调用处,消除函数调用的开销,提高执行效率。 **形象比喻**: - **普通函数**:就像打电话,需要拨号、等待接通、通话、挂断,有很大的开销 - **内联函数**:就像面对面交谈,直接传递信息,几乎没有开销
  2. 语法

    inline 返回值类型 函数名(形参列表); inline int add(int a, int b) { //函数体 }

    语法原则

    1. 函数的语句小于等于5行:函数体过于庞大时,内联展开会导致代码体积急剧增加

      // 不适合内联:函数体过大 inline int computeSum(int arr[], int size) { int sum = 0; for (int i = 0; i < size; i++) { // 有循环 sum += arr[i]; } return sum; }
    2. 函数内没有循环结构:循环会导致代码重复展开,增加代码体积

      // 不适合内联:函数体过大 inline int computeSum(int arr[], int size) { int sum = 0; for (int i = 0; i < size; i++) { // 有循环 sum += arr[i]; } return sum; }
    3. 函数不能递归:递归函数无法在编译时确定展开次数

      // 不适合内联:递归函数 inline int factorial(int n) { if (n == 0) return 1; return n * factorial(n - 1); // 递归 }
  3. 工作原理

    //普通函数调用: int add(int a, int b) { return a + b; } int main() { int x = add(3, 5); // 编译后:call add return 0; } //内联函数展开 inline int add(int a, int b) { return a + b; } int main() { int x = add(3, 5); // 编译后:int x = 3 + 5; return 0; } //编译器会将 `add(3, 5)` 直接替换为函数体 `3 + 5`,从而避免了函数调用的开销。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询