C++ 入门核心知识点(从 C 过渡到 C++ 基础) - 教程

一、C++ 第一个程序:兼容 C 与标准 C++ 版本

        C++ 完全兼容 C 语言语法,同时提供了更简洁的标准库用法,两个经典 "Hello World" 实现如下:

1. 兼容 C 语言版本

        直接使用 C 语言的stdio.h库,写法与 C 完全一致:

#include 
int main()
{
	printf("Hello World!\n");
	return 0;
}

2. 标准 C++ 版本

        使用 C++ 标准输入输出库iostream,通过cout输出(需配合命名空间std):

#include 
using namespace std; // 展开std命名空间(后续详解)
int main()
{
	cout << "Hello World" << endl; // 流插入运算符<<,endl=换行+刷新缓冲区
	return 0;
}

二、命名空间

        C 语言中没有命名空间概念,当多个文件或库定义同名变量 / 函数时,会出现命名冲突。C++ 的namespace正是为解决此问题而生。

1. C 语言的命名冲突问题

#include 
#include  // 该库中定义了rand()函数
int rand = 10; // 错误:与stdlib.h中的rand函数重定义冲突
int main()
{
	printf("%d\n", rand);
	return 0;
}

        编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”

2. 命名空间的定义与本质

  • 定义语法namespace 命名空间名 { 变量/函数/类型定义 }
  • 本质:创建一个独立的作用域(域),与全局域相互独立,同名标识符在不同域中可共存
  • 特性
    • 命名空间只能定义在全局域,支持嵌套定义
    • 多文件中同名的命名空间会被合并为一个(不会冲突)
    • 不影响变量生命周期(仅影响访问范围)
#include 
#include 
// 定义命名空间a,内部可定义变量、函数、结构体
namespace a
{
	int rand = 10; // 与stdlib.h的rand无冲突
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}
// 嵌套命名空间
namespace a
{
	namespace x
	{
		int rand = 1;
	}
	namespace y
	{
		int rand = 2;
	}
}
int main()
{
	// 访问命名空间中的成员需用域作用限定符::
	printf("%d\n", a::rand);	    // 10(访问a域的rand)
	printf("%d\n", a::x::rand);	// 1(访问a::x域的rand)
	printf("%d\n", a::Add(1, 1));	// 2(访问a域的Add函数)
	struct a::Node p1; // 定义a域的Node类型变量
	p1.val = 6;
	printf("%d\n", p1.val); // 6
	return 0;
}

3. 域作用限定符::与命名空间使用方式

  • 域作用限定符:指定访问的作用域,::变量名访问全局域命名空间名::变量名访问指定命名空间域
  • 命名空间 3 种使用方式
    1. 指定命名空间访问(推荐):s::a
    2. 展开单个成员:using s::b
    3. 展开所有成员(仅小练习使用):using namespace s
int m = 0; // 全局变量m
int main()
{
	int m = 1;
	printf("%d ", m);	// 1(局部m)
	printf("%d ", ::m);	// 0(全局m,显式加::)
	namespace s { int a=0, b=1; }
	using s::b; // 展开单个成员
	printf("%d\n", b); // 1
	return 0;
}

注意:C++ 标准库(如coutcin)都放在std命名空间中,日常练习可using namespace std简化代码,实际项目建议用指定命名空间访问(如std::cout)。

三、C++ 输入输出

        C++ 提供iostream库,通过cin(输入)和cout(输出)实现 IO 操作,相比 C 语言的scanf/printf更灵活:

  • 无需手动指定格式(如%d%f),自动识别变量类型(本质是函数重载)
  • 支持链式操作(cout << a << bcin >> a >> b
  • endl:等价于\n+ 刷新缓冲区
  • 需通过std命名空间访问
#include 
using namespace std;
int main()
{
	// 竞赛级IO优化(大量输入输出场景使用)
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	// 输出
	int i = 1;
	double j = 3.14;
	cout << "i = " << i << endl;	   // i = 1
	cout << "j = " << j << endl;	   // j = 3.14
	// 输入
	int a;
	char c;
	cin >> a >> c; // 链式输入
	cout << "a = " << a << ", c = " << c << endl;
	return 0;
}

四、缺省参数(默认参数)

 缺省参数是声明或定义函数时为参数指定默认值,调用时若未传实参则使用默认值,否则使用实参。

  • 全缺省参数:所有参数都指定默认值
  • 半缺省参数:部分参数指定默认值(必须从右往左连续缺省,不能跳跃)
  • 声明与定义分离:缺省参数只能在声明中指定
#include 
using namespace std;
// 全缺省参数
void Func1(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << ", b = " << b << ", c = " << c << endl;
}
// 半缺省参数(从右往左连续缺省)
void Func2(int a, int b = 10, int c = 20)
{
	cout << "a = " << a << ", b = " << b << ", c = " << c << endl;
}
int main()
{
	Func1();		  // a=10, b=20, c=30
	Func1(1, 2);	  // a=1, b=2, c=30
	Func2(100);		  // a=100, b=10, c=20
	Func2(100, 200, 300); // a=100, b=200, c=300
	return 0;
}

五、函数重载

        C++ 支持同一作用域中定义同名函数,只要形参不同(个数、类型、顺序不同),称为函数重载,实现多态行为。

  • 重载条件:形参不同(个数、类型、顺序),与返回值无关
  • 避免歧义:调用时需让编译器能明确区分同名函数
#include 
using namespace std;
// 1. 形参类型不同
int Add(int left, int right) { cout << "int Add\n"; return left+right; }
double Add(double left, double right) { cout << "double Add\n"; return left+right; }
// 2. 形参个数不同
void f() { cout << "f()\n"; }
void f(int a) { cout << "f(int a)\n"; }
// 3. 形参顺序不同
void f(int a, char b) { cout << "f(int, char)\n"; }
void f(char b, int a) { cout << "f(char, int)\n"; }
int main()
{
	Add(10, 20);		  // int版本
	Add(10.1, 20.2);	  // double版本
	f(10, 'a');			  // int+char版本
	f('a', 10);			  // char+int版本
	return 0;
}

      错误示例:

// 错误1:仅返回值不同,不构成重载
// void f() {}
// int f() { return 0; }
// 错误2:调用歧义
void f1() {}
void f1(int a = 10) {}
// f1(); // 报错:无法区分

六、引用

引用是给已存在变量取的别名,编译器不会为引用开辟内存空间,与原变量共用同一块内存。

1. 定义语法与特性

类型& 引用别名 = 原变量;
  • 必须初始化
  • 一个变量可以有多个引用
  • 一旦绑定某个变量,就不能再绑定其他变量
#include 
using namespace std;
// 引用传参(替代指针传参)
void Swap(int& rx, int& ry)
{
	int tmp = rx;
	rx = ry;
	ry = tmp;
}
int main()
{
	int a = 0;
	int& b = a; // b是a的别名
	++b;
	cout << a << endl; // 1(a被修改)
	int x = 0, y = 1;
	Swap(x, y); // 直接传变量,无需取地址
	cout << x << " " << y << endl; // 1 0
	return 0;
}

2. const 引用(关键用法)

const 引用用于:传参时不拷贝原变量、不修改原变量,或引用临时对象(临时对象具有常性)。

#include 
using namespace std;
int main()
{
	const int a = 10;
	const int& ra = a; // 正确:const引用引用const变量
	int b = 20;
	const int& rb = b; // 正确:权限缩小(b可修改,rb只读)
	// rb++; // 错误:const引用不可修改
	// 引用临时对象(必须用const引用)
	const int& rc = 30; // 正确
	double d = 12.34;
	const int& rd = d; // 正确(类型转换产生临时对象)
	return 0;
}

3.引用与指针的核心区别

特性引用指针
内存空间不开辟空间(共用原变量空间)开辟空间(存储变量地址)
初始化必须初始化建议初始化(可置空)
指向修改一旦绑定,不能修改指向可随时修改指向
访问方式直接访问(无需解引用)需解引用(*)访问目标变量
安全性无空引用 / 野引用(更安全)存在空指针 / 野指针(风险高)

七、inline:内联函数(替代 C 语言宏函数)

inline修饰的函数叫做内联函数,编译时编译器会在调用处展开函数体,避免函数调用的栈帧开销,提高效率。

  • inline是编译器的建议,长函数、递归函数会被编译器忽略
  • 替代 C 语言宏函数(宏函数易出错、不便调试)
  • 不建议声明和定义分离(会导致链接错误)
#include 
using namespace std;
// 内联函数(短函数,频繁调用场景)
inline int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int ret = Add(1, 2); // 编译时展开为:int ret = 1 + 2;
	cout << ret << endl; // 3
	return 0;
}

        与 C 语言宏函数的对比:C 语言宏函数需注意优先级和分号问题,而 inline 函数更安全。

// C语言宏函数(需加多层括号,避免优先级问题)
#define ADD(a,b) ((a)+(b))
// C++ inline函数(无需担心优先级,支持调试)
inline int Add(int a, int b) { return a + b; }

八、nullptr

  nullptrC++11 引入的关键字,用于替代 C 语言中的NULL,解决了NULL在类型转换和函数重载中的歧义问题。

1. C 语言中 NULL 的缺陷

        C 语言中NULL是宏定义,C++ 中常定义为0,导致函数重载歧义:

#include 
using namespace std;
void f(int x) { cout << "f(int x)\n"; }
void f(int* ptr) { cout << "f(int* ptr)\n"; }
int main()
{
	f(NULL); // 输出:f(int x)(歧义!本意是调用指针版本)
	return 0;
}

2. nullptr 的核心特性与使用

  • 类型为std::nullptr_t,可隐式转换为任意指针类型,但不能转换为整数类型
  • 精准匹配指针类型的重载函数,无歧义
#include 
using namespace std;
void f(int x) { cout << "f(int x)\n"; }
void f(int* ptr) { cout << "f(int* ptr)\n"; }
int main()
{
	f(nullptr); // 输出:f(int* ptr)(精准匹配)
	// 类型安全:不能转换为整数
	// int x = nullptr; // 编译报错
	// 可隐式转换为任意指针类型
	int* p1 = nullptr;
	char* p2 = nullptr;
	return 0;
}

3. NULL 与 nullptr 对比

特性NULLnullptr
本质宏定义(可能为 0 或 void*)关键字(类型为 std::nullptr_t)
函数重载匹配可能匹配 int 版本(歧义)精准匹配指针版本(无歧义)
类型转换可转换为 int 或指针仅可转换为指针(类型安全)

        如果有疑问或补充,欢迎在评论区交流~

posted on 2025-12-21 16:54  ljbguanli  阅读(0)  评论(0)    收藏  举报