一、C++的起源与特性
C++是由Bjarne Stroustrup在1980年代初设计的一种编程语言。
它在C语言的基础上进行了扩展和优化,不仅继承了C语言的高效性和灵活性,还引入了面向对象编程、异常处理、泛型编程等现代编程特性。
C++是一种编译型语言,具有强类型检查,支持多种编程范式,语言风格简洁且功能强大。
C++的主要特性
-
编译型语言:C++代码需要先通过编译器编译成机器代码,然后才能运行。
-
强类型语言:变量的类型在声明时必须明确,不同类型之间不能随意转换。
-
与C语言完全兼容:C++对C语言完全兼容,可以无缝运行C语言代码。
-
面向对象编程:支持类、继承、多态等面向对象特性。
-
异常处理 :支持
try
、catch
和throw
等异常处理机制。 -
泛型编程:通过模板支持泛型编程,提高代码的复用性。
-
操作符重载:允许对操作符进行重载,使代码更加直观。
二、C++的第一个程序:Hello World
编写C++程序的第一步是创建一个简单的"Hello World"程序。
这个程序可以帮助我们熟悉C++的基本语法和开发环境。
以下是使用g++编译器编写的"Hello World"程序示例:
cpp
#include <iostream> // 包含输入输出流库
using namespace std; // 使用标准名字空间
int main() {
cout << "Hello, World!" << endl; // 输出字符串到控制台
return 0; // 程序正常结束
}
代码解析
-
#include <iostream>
:包含标准输入输出流库,用于支持输入输出操作。 -
using namespace std;
:声明使用标准名字空间std
,这样可以直接使用cout
和cin
等标准输入输出对象。 -
cout
:标准输出流对象,用于向控制台输出内容。 -
endl
:换行符,同时刷新输出缓冲区。 -
main
函数:程序的入口点,程序从这里开始执行。
三、名字空间:组织代码的利器
名字空间是C++中用于避免命名冲突和组织代码的重要机制。通过定义名字空间,可以将相关的变量、函数和类等封装在一起,避免不同模块之间的名称冲突。
1. 名字空间的定义
名字空间的定义使用namespace
关键字,例如:
cpp
namespace MyNamespace {
int value = 42; // 定义一个整型变量
void display() { // 定义一个成员函数
cout << "Value: " << value << endl;
}
}
cpp
//名字空间:划分更多的逻辑空间(逻辑单元,作用域),可以效避免名字冲突
# include <iostream>// 引入输入输出流库
namespace ICBC // 定义一个名为ICBC的命名空间
{
int g_money = 0;// 全局变量,存储银行账户余额
void save(int money)// 函数声明,存钱
{
g_money += money;// 将money存入全局变量g_money
}
}
namespace ICBC// 编译器会将所有在这个命名空间内的代码视为一个逻辑单元
{
void pay(int money) // 函数声明,取钱
{
g_money -= money;// 从全局变量g_money中取出money
}
}
namespace CCB// 定义一个名为CCB的命名空间
{
int g_money = 0;// 全局变量,存储银行账户余额
void save(int money)// 函数声明,存钱
{
g_money += money;// 将money存入全局变量g_money
}
void pay(int money) // 函数声明,取钱
{
g_money -= money;// 从全局变量g_money中取出money
}
}
int main(void)// 主函数入口
{
ICBC::save(10000);// 存钱
ICBC::pay(3000);// 取钱
std::cout << "工行卡余额:" << ICBC::g_money << std::endl;// 输出余额
CCB::save(10000);// 存钱
CCB::pay(3000);// 取钱
std::cout << "建行卡余额:" << CCB::g_money << std::endl;// 输出余额
return 0;
}
2. 使用名字空间
使用名字空间时,可以通过作用域限定符::
来访问其内部的成员,例如:
cpp
int main() {
cout << MyNamespace::value << endl; // 访问名字空间中的变量
MyNamespace::display(); // 调用名字空间中的函数
return 0;
}
此外,还可以使用名字空间指令using namespace
来简化代码,但需注意避免命名冲突。例如:
cpp
using namespace MyNamespace; // 使用名字空间
int main() {
cout << value << endl; // 直接访问变量
display(); // 直接调用函数
return 0;
}
cpp
/* 2025年7月27日18:45:03
名字空间指令 */
# include <iostream>
namespace ns
{
int g_value = 0; // 全局变量,存储值
}
int main (void)
{
int g_value = 0;//
using namespace ns; //从这行代码开始,ns中的内容在当前作用域,可见
g_value = 100; // 使用命名空间ns中的全局变量g_value
std::cout << "ns:: g_value = " << ns::g_value << std::endl; // 输出命名空间ns中的全局变量g_value的值
return 0; // 返回0表示程序正常结束
}
3. 名字空间嵌套与别名
名字空间可以嵌套,内层标识符与外层同名标识符为隐藏关系。嵌套的名字空间需要逐层分解。例如:
cpp
namespace ns1 {
namespace ns2 {
int value = 42;
}
}
int main() {
cout << ns1::ns2::value << endl; // 访问嵌套名字空间中的变量
return 0;
}
为了简化书写,可以使用名字空间别名:
cpp
namespace ns_four = ns1::ns2::ns3::ns4; // 定义名字空间别名
int main() {
cout << ns_four::value << endl; // 使用别名访问变量
return 0;
}
四、C++的复合类型
C++提供了多种复合类型,包括结构体、联合体和枚举类型,这些类型可以帮助我们更好地组织和管理数据。
1. 结构体
结构体是一种用户自定义的数据类型,可以包含多个不同类型的成员变量。在C++中,结构体可以定义成员函数,成员函数可以直接访问结构体的成员。
cpp
struct Person {
string name; // 成员变量
int age; // 成员变量
void display() { // 成员函数
cout << "Name: " << name << ", Age: " << age << endl;
}
};
int main() {
Person p = {"Alice", 30}; // 创建结构体对象
p.display(); // 调用成员函数
return 0;
}
2. 联合体
联合体是一种特殊的结构体,其所有成员共享同一块内存。在C++中,联合体可以定义匿名联合,用于简化代码。
cpp
union Data {
int i; // 成员变量
float f; // 成员变量
char str[20]; // 成员变量
};
int main() {
Data data;
data.i = 10; // 给成员变量赋值
cout << "Data.i: " << data.i << endl;
return 0;
}
3. 枚举类型
枚举类型是一种独立的类型,用于定义一组命名的整数值。在C++中,枚举类型与整型之间不能隐式转换。
cpp
enum Color { RED, GREEN, BLUE }; // 定义枚举类型
int main() {
Color c = GREEN; // 创建枚举变量
cout << "Color: " << c << endl; // 输出枚举变量的值
return 0;
}
五、函数重载与缺省参数
函数重载是C++中一种重要的特性,允许在同一个作用域内定义多个同名函数,只要它们的参数列表不同即可。重载解析是根据实参类型和形参类型进行匹配,调用最匹配的函数版本。
1. 函数重载
cpp
void display(int x) { // 定义第一个重载函数
cout << "Integer: " << x << endl;
}
void display(float x) { // 定义第二个重载函数
cout << "Float: " << x << endl;
}
int main() {
display(10); // 调用第一个重载函数
display(10.5f); // 调用第二个重载函数
return 0;
}
2. 缺省参数
缺省参数允许为函数的形参指定默认值,当调用函数时未指定实参时,将使用默认值。
cpp
void display(int x, int y = 42) { // 定义函数,为第二个参数指定默认值
cout << "x: " << x << ", y: " << y << endl;
}
int main() {
display(10); // 使用默认值y=42
display(10, 20); // 显式指定第二个参数
return 0;
}
3. 重载解析
重载解析的规则如下:
-
完全匹配:优先选择完全匹配的函数。
-
常量转换:如果完全匹配失败,尝试将参数转换为常量。
-
升级转换:如果常量转换失败,尝试将参数升级为更高级的类型。
-
标准转换:如果升级转换失败,尝试进行标准类型转换。
-
自定义转换:如果标准转换失败,尝试使用自定义的类型转换。
-
省略号匹配:如果所有转换都失败,尝试使用省略号匹配。