数组
需要预先了解: 变量与常量 数组 数组(Array):同一类型数据的连续内存集合。 数组中的所有元素的类型都相同,并且长度固定,C++中可以用[]运算符来定义数组: // 类型 数组名[数组长度] int arr[5]; // 长度为5的 int 类型的整数数组 char str[100]; // 长度为100的 char 类型变量的字符数组(字符串) 通过[]运算符来访问数组元素 数组的下标索引从0开始: int main() { int arr[5]; arr[0] = 10; arr[4] = 50; arr[5] = 100; // 错误,arr的下标范围是0~4,没有5 } 常量数组 可以在定义数组的时候用const关键字来修饰数组元素,使得数组的每一个元素的值都不能被修改。 #include <iostream> int main() { const int arr[5] = ...
数组名退化为指针
需要预先了解: 数组 指针 数组到指针的退化 数组名出现在大多数表达式中,会被编译器自动转化为指向数组首元素的指针: int arr[5] = { 1, 2, 3, 4, 5 }; int* p = arr; // arr 这里的含义为 &arr[0],类型为 int* 1. 下标访问arr[i]在底层等价于*(arr + i) 甚至可以可以有3[arr]这样的写法,和arr[3]等效: #include <iostream> int main() { int arr[5] = { 1, 2, 3, 4, 5 }; std::cout << 3[arr] << std::endl; // 并不建议的写法 return 0; } 2. 可以用指针的方式访问数组,或用数组的方式访问指针 #include <iostream> int main() { int arr[5] = { ...
函数
函数 函数是 C++ 程序中用于封装可执行逻辑的基本单元,将一段完成特定功能的代码组织为可复用的整体。定义函数的语法如下: 返回值类型 函数名(参数类型1 参数1, 参数类型2 参数2, ...) { // 函数体,执行具体的逻辑 return 返回值; } 注: 对于返回值类型为void的函数,可以不写return语句,或直接写return;提前终止。 函数的声明与定义 函数的声明和定义是两个不同的概念,遵循单一定义规则(ODR):一个程序中函数只能有一次定义,但可以有多次声明。 函数声明:也叫函数原型,仅告诉编译器函数的名称、返回类型和参数列表,不包含函数体。 函数定义:包含完整的函数体,是函数的具体实现。 int add(int a, int b); // 函数声明 int main() { int res = add(10, 2); // 在声明后即可调用函数 return 0; } int add(int a, int b) // 函数定义 { ...
函数参数的值传递与引用传递、指针传递的区别
需要预先了解: 函数 引用与左右值 指针 形参与实参 形式参数(Parameter) 形参是函数定义或函数声明时,在参数列表中声明的变量,是函数内部用来接收外部数据的占位符。 函数未被调用时,不占用实际内存 函数被调用时,创建并初始化 函数执行结束后立即销毁 实际参数(Argument) 实参是调用函数时传递给函数的具体数据。 // a、b是形参 int add(int a, int b) { return a + b; } int main() { int x = 10, y = 20; // x+y、x*y是实参 int res = add(x + y, x * y); return 0; } 值传递 形参是实参的一份独立拷贝,形参与实参占有不同的内存地址。 函数内对形参的修改都不会作用于外部的实参 如果参数的内存占用过大,频繁地拷贝会导致明显的性能问题 void swap(int x, int y) { int temp =...
类与对象
需要预先学习: 变量与常量 函数 类与对象 前面学习的 int、double 等内置类型只能表示单个数据。当你想描述一个学生——有姓名、学号、成绩,还会做自我介绍——散落的几个变量无法把"数据"和"操作"组织在一起。C++ 为此提供了类(class)机制,让你可以定义自己的类型。 类(class):一种用户自定义类型,描述一类事物共有的特征(数据)和行为(操作)。 对象(object):类的具体实例(instance),每个对象都拥有自己的一份数据。 比如"人"是一个类——所有人都有名字、年龄,都会打招呼,这些共性是"人"这个类描述的;而张三、李四则是两个具体的对象,他们拥有同样的结构,但名字、年龄各不相同。 类与对象的关系,就像图纸和按图纸造出来的实物:图纸只有一份,不占实际空间;每按图纸造出一个实物,都要占用真实的空间。对应到程序中:类本身不占内存,每实例化一个对象,就会分配一块独立的内存。 类的定义 用 class 关键字定义类: #include <iostr...
封装
需要预先学习: 类与对象 封装 封装(encapsulation)有两层含义: 把数据(成员变量)和操作数据的行为(成员函数)打包到类中 通过访问权限限定符控制谁能访问这些成员,把实现细节藏起来 在 类与对象 里,成员统一用了 public,任何代码都能直接读写成员变量。这带来一个问题:如果有人给 m_age 赋了 -1,程序照单全收,对象就处于“年龄是负数”的非法状态。封装要做的,就是收起成员的直接访问权,只通过类提供的成员函数来操作数据,由类自己守住数据的合法性。 访问权限限定符 C++ 提供三种访问权限限定符,用它们把类体分成几个区域: 限定符 类内部 类外部 public 可访问 可访问 private 可访问 不可访问 protected 可访问 不可访问 private 与 protected 在"类外部不可访问"上是一致的,区别在于继承时派生类能否访问(详见 继承)。本节统一用 private 表示私有成员。 #include <iostream> #include <s...
继承
需要预先学习: 类与对象 封装 继承 继承(inheritance)让一个新类可以获得另一个类的成员,从而复用代码,并表达"是一种"(is-a)的关系。 学生、教师都是人,都有姓名、年龄,都会打招呼。把这些共性提取到 Person 类里,让 Student、Teacher 从它继承,各自只需写独有的部分——不必把姓名、年龄在每个类里重复一遍。 基类(base class,也叫父类):被继承的类 派生类(derived class,也叫子类):继承别人的类 “学生是一个人”——这种 is-a 关系是继承的核心:派生类对象可以当作基类对象来用。 继承的语法 继承写在类名后面的冒号处: class Student : public Person // Student 公开继承 Person { // 这里只需写 Student 独有的成员 }; #include <iostream> #include <string> class Person { public: st...
多态
需要预先学习: 类与对象 继承 多态 多态(polymorphism)的字面意思是"多种形态":同一个调用形式,根据对象的实际类型表现出不同的行为。 C++ 中的多态分为两类: 静态多态(编译期多态):函数重载、模板,调用哪个版本在编译期就确定 动态多态(运行期多态):虚函数,调用哪个版本在程序运行时才确定 静态多态 函数重载是静态多态的典型:同一个函数名,参数列表不同,编译时根据实参类型决定调用哪个版本。 #include <iostream> void print(int x) { std::cout << "整数:" << x << std::endl; } void print(double x) { std::cout << "浮点数:" << x << std::endl; } int main() { print(10); // 编译时确定调用 print(int...
类的内存占用
需要预先了解: 类与对象 内存基础 多态 类的实例的内存占用 类的实例(对象)的内存占用,指的是 sizeof(类名) 的结果——它只统计数据成员和编译器为支持语言特性而插入的隐藏成员(如虚表指针),不包含静态成员变量和成员函数。先看一组真实测量(64 位平台): #include <cstdio> class Empty {}; // 空类 class WithInt { public: int x; }; class WithVirt { public: virtual void f() {} int x; }; class WithStatic { public: static int s; // 静态成员变量 int x; }; int WithStatic::s = 0; int main() { prin...
extern、static 与 inline 关键字总结
需要预先了解: 变量与常量 函数 内存基础 extern、static、inline 修饰变量时的区别 三个关键字修饰变量时,本质都在操纵声明与定义的关系和链接属性(linkage)。要理解它们的区别,先要弄清楚链接是怎么回事。 翻译单元与链接 一个 C++ 程序通常由多个 .cpp 文件组成。每个 .cpp 文件连同它 #include 的所有头文件,构成一个翻译单元(translation unit)。编译器逐个翻译单元独立编译,产出目标文件(.o),链接器(linker)再把所有目标文件合并成可执行文件。 每个翻译单元中定义的全局变量和函数,都会在目标文件里生成一个符号(symbol)——它是链接器用来识别"哪个名字对应哪块地址"的索引。链接器需要回答一个关键问题:a.cpp 里用到了 global,该去哪里找它的定义?答案取决于符号的链接属性: 外部链接(external linkage):符号对其他翻译单元可见,链接器可以在整个程序范围内解析它 内部链接(internal linkage):符号只在本翻译单元内可见,...


