C++ 入门 FAQ
C++ 基本语法
变量和类型
int a = 10;
double b = 20.5;
char c = 'A';
条件语句
if (a > b) {
// 代码块
} else {
// 代码块
}
循环语句
for (int i = 0; i < 10; i++) {
// 代码块
}
while (a < b) {
// 代码块
}
函数
int add(int x, int y) {
return x + y;
}
类和对象
class MyClass {
public:
int myNumber;
void myFunction() {
// 代码块
}
};
``` C++ 示例说明基本语法
本文档介绍了 C++ 的基本语法示例,帮助初学者快速上手 C++ 编程。
变量和数据类型
```cpp
#include <iostream>
using namespace std;
int main() {
int myNum = 5; // 整型变量
double myFloatNum = 5.99; // 浮点型变量
char myLetter = 'D'; // 字符型变量
string myText = "Hello"; // 字符串变量
bool myBoolean = true; // 布尔型变量
cout << myNum << endl;
cout << myFloatNum << endl;
cout << myLetter << endl;
cout << myText << endl;
cout << myBoolean << endl;
return 0;
}
在 C++ 里,class(类)是面向对象编程的关键概念,public、private 和 protected 这几个访问修饰符在类中起着至关重要的作用,它们用于控制类成员(包括数据成员和成员函数)的访问权限。以下为你详细介绍:
访问修饰符的作用
public:使用public修饰的成员可以在类的外部被自由访问。也就是说,类的对象可以直接调用这些成员。private:private修饰的成员只能在类的内部被访问,类的外部无法直接访问这些成员。这有助于实现数据封装和信息隐藏,提高代码的安全性和可维护性。protected:protected修饰的成员可以在类的内部以及该类的派生类(子类)中被访问,但在类的外部不能直接访问。
代码示例
#include <iostream>
#include <string>
class Person {
private:
// 私有数据成员,只能在类的内部访问
std::string name;
int age;
public:
// 公有成员函数,用于设置姓名
void setName(const std::string& newName) {
name = newName;
}
// 公有成员函数,用于设置年龄
void setAge(int newAge) {
age = newAge;
}
// 公有成员函数,用于获取姓名
std::string getName() const {
return name;
}
// 公有成员函数,用于获取年龄
int getAge() const {
return age;
}
};
int main() {
// 创建 Person 类的对象
Person person;
// 通过公有成员函数设置姓名和年龄
person.setName("Alice");
person.setAge(25);
// 通过公有成员函数获取姓名和年龄并输出
std::cout << "Name: " << person.getName() << std::endl;
std::cout << "Age: " << person.getAge() << std::endl;
// 以下代码会报错,因为 name 和 age 是私有成员,不能在类的外部直接访问
// person.name = "Bob";
// std::cout << person.age << std::endl;
return 0;
}
代码解释
private部分:name和age是私有数据成员,在类的外部无法直接访问。这样做的好处是可以防止外部代码随意修改这些数据,保证数据的安全性和完整性。public部分:提供了四个公有成员函数setName、setAge、getName和getAge,用于在类的外部间接访问和修改私有数据成员。通过这种方式,可以对数据的访问进行控制,例如在setAge函数中可以添加年龄的有效性检查。
继承中的 protected 访问修饰符
protected 访问修饰符在继承关系中发挥着重要作用。以下是一个简单的示例:
#include <iostream>
class Base {
protected:
int protectedVar;
public:
Base() : protectedVar(0) {}
};
class Derived : public Base {
public:
void setProtectedVar(int value) {
// 可以在派生类中访问基类的 protected 成员
protectedVar = value;
}
int getProtectedVar() const {
return protectedVar;
}
};
int main() {
Derived derived;
derived.setProtectedVar(10);
std::cout << "Protected variable value: " << derived.getProtectedVar() << std::endl;
return 0;
}
在这个示例中,Base 类的 protectedVar 成员可以在 Derived 类中被访问,但在 main 函数中不能直接访问。这体现了 protected 访问修饰符在继承关系中的特性。
条件语句
#include <iostream>
using namespace std;
int main() {
int x = 20;
int y = 18;
if (x > y) {
cout << "x is greater than y";
} else {
cout << "x is not greater than y";
}
return 0;
}
循环
#include <iostream>
using namespace std;
int main() {
for (int i = 0; i < 5; i++) {
cout << i << "\n";
}
return 0;
}
函数
#include <iostream>
using namespace std;
void myFunction() {
cout << "I just got executed!";
}
int main() {
myFunction();
return 0;
}
类和对象
#include <iostream>
using namespace std;
class MyClass {
public:
int myNum;
string myString;
};
int main() {
MyClass myObj;
myObj.myNum = 15;
myObj.myString = "Some text";
cout << myObj.myNum << "\n";
cout << myObj.myString;
return 0;
}
数据类型
C++ 提供了多种数据类型,用于存储不同类型的值。以下是一些常见的数据类型:
| 数据类型 | 关键字 | 描述 |
|---|---|---|
| 整型 | int | 存储整数(不带小数) |
| 浮点型 | float | 存储单精度浮点数(带小数) |
| 双精度型 | double | 存储双精度浮点数(带小数) |
| 字符型 | char | 存储单个字符 |
| 布尔型 | bool | 存储布尔值(true 或 false) |
| 字符串型 | string | 存储字符串(需要包含 <string> 头文件) |
示例
#include <iostream>
using namespace std;
int main() {
int myNum = 10; // 整型
float myFloat = 5.75; // 浮点型
double myDouble = 19.99; // 双精度型
char myChar = 'A'; // 字符型
bool myBool = true; // 布尔型
string myString = "Hello"; // 字符串型
cout << "int: " << myNum << endl;
cout << "float: " << myFloat << endl;
cout << "double: " << myDouble << endl;
cout << "char: " << myChar << endl;
cout << "bool: " << myBool << endl;
cout << "string: " << myString << endl;
return 0;
}
常量
常量是固定值,在程序执行期间不会改变。这些固定值称为字面量。常量可以是任何基本数据类型的常量。
常量的定义
在 C++ 中,可以使用 const 关键字来定义常量:
#include <iostream>
using namespace std;
int main() {
const int myNum = 10; // 整型常量
const float myFloat = 5.75; // 浮点型常量
const char myChar = 'A'; // 字符型常量
const string myString = "Hello"; // 字符串常量
cout << "int: " << myNum << endl;
cout << "float: " << myFloat << endl;
cout << "char: " << myChar << endl;
cout << "string: " << myString << endl;
return 0;
}
宏定义常量
可以使用 #define 预处理器指令来定义常量:
#include <iostream>
#define PI 3.14159
#define NEWLINE '\n'
using namespace std;
int main() {
cout << "Value of PI: " << PI << NEWLINE;
return 0;
}
C++常量通常不可变
在 C++ 中,常量通常是不可变的,但具体情况需要根据常量的类型和定义方式来详细分析,以下为你展开介绍:
- 字面值常量
- 概念:字面值常量是在代码中直接写出的值,如整数、浮点数、字符、字符串等。
- 特性:它们在程序运行期间是不可改变的。例如:
#include <iostream>
int main() {
// 整数字面值常量
10 = 20; // 错误,不能对字面值常量进行赋值操作
return 0;
}
在上述代码中,试图对整数字面值常量 10 进行赋值,这会导致编译错误,因为字面值常量是不可修改的。
- 使用
const关键字定义的常量
- 基本类型常量
- 当使用
const关键字修饰基本数据类型(如int、double等)的变量时,该变量成为常量,其值在初始化后不能被修改。
- 当使用
#include <iostream>
int main() {
const int num = 10;
num = 20; // 错误,不能对 const 常量进行赋值
return 0;
}
在这个例子中,num 被定义为 const int 类型的常量,尝试对其重新赋值会引发编译错误。
- 指针常量和常量指针
- 常量指针:指针指向的对象是常量,不能通过该指针修改对象的值,但指针本身可以指向其他对象。
#include <iostream>
int main() {
int num1 = 10;
int num2 = 20;
const int* ptr = &num1;
// *ptr = 20; // 错误,不能通过常量指针修改指向对象的值
ptr = &num2; // 正确,指针本身可以指向其他对象
return 0;
}
- **指针常量**:指针本身是常量,不能指向其他对象,但可以通过该指针修改指向对象的值。
#include <iostream>
int main() {
int num1 = 10;
int num2 = 20;
int* const ptr = &num1;
*ptr = 20; // 正确,可以通过指针常量修改指向对象的值
// ptr = &num2; // 错误,指针本身不能指向其他对象
return 0;
}
constexpr常量表达式
- 概念:
constexpr关键字用于声明常量表达式,它在编译时就可以计算出结果,并且其值在程序运行期间不可改变。
#include <iostream>
constexpr int square(int x) {
return x * x;
}
int main() {
constexpr int result = square(5);
// result = 20; // 错误,不能对 constexpr 常量进行赋值
std::cout << result << std::endl;
return 0;
}
在这个例子中,result 是一个 constexpr 常量,其值在编译时就确定了,不能在运行时修改。
- 特殊情况:
const_cast强制类型转换(不推荐)
虽然常量在正常情况下不可变,但可以使用const_cast进行强制类型转换来去除const限定符,但这种做法是不安全的,可能会导致未定义行为:
#include <iostream>
int main() {
const int num = 10;
int* ptr = const_cast<int*>(&num);
*ptr = 20; // 未定义行为
std::cout << num << std::endl;
return 0;
}
在这个例子中,使用 const_cast 去除了 num 的 const 限定符,但修改 const 对象的值是未定义行为,不应该在实际编程中使用。
综上所述,C++ 中的常量在大多数情况下是不可变的,这有助于提高程序的安全性和可维护性。
指针常量和常量指针
指针常量和常量指针不是一回事,下面从概念、声明方式、特性等方面为你详细介绍二者的区别:
常量指针(指向常量的指针)
概念
常量指针是一种指针,该指针指向的对象是常量,意味着不能通过该指针来修改所指向对象的值,但指针本身的值(即它所指向的地址)是可以改变的。
声明方式
声明常量指针时,const 关键字位于数据类型之后,指针声明符 * 之前。示例如下:
const int* ptr;
特性
- 不能通过指针修改指向的值:由于所指向的对象被视为常量,所以不能通过该指针来修改对象的值。
- 指针本身可以改变:可以让指针指向其他对象。
示例代码
#include <iostream>
int main() {
int num1 = 10;
int num2 = 20;
// 声明一个常量指针
const int* ptr = &num1;
// 以下语句会报错,因为不能通过常量指针修改指向的值
// *ptr = 15;
// 指针可以指向其他对象
ptr = &num2;
std::cout << *ptr << std::endl;
return 0;
}
指针常量(常量指针)
概念
指针常量是一种指针,该指针本身是常量,意味着指针一旦初始化后,就不能再指向其他对象,但可以通过该指针修改所指向对象的值。
声明方式
声明指针常量时,const 关键字位于指针声明符 * 之后。示例如下:
int* const ptr;
特性
- 指针本身不能改变:指针一旦初始化后,就不能再指向其他对象。
- 可以通过指针修改指向的值:由于指针所指向的对象不是常量,所以可以通过该指针来修改对象的值。
示例代码
#include <iostream>
int main() {
int num = 10;
// 声明一个指针常量并初始化
int* const ptr = #
// 可以通过指针修改指向的值
*ptr = 15;
std::cout << *ptr << std::endl;
// 以下语句会报错,因为指针本身是常量,不能再指向其他对象
// int num2 = 20;
// ptr = &num2;
return 0;
}
总结
- 常量指针侧重于保护所指向对象的值不被修改,指针本身可以指向其他对象。
- 指针常量侧重于固定指针的指向,一旦初始化就不能再指向其他对象,但可以修改所指向对象的值。
变量作用域
变量的作用域是程序中变量可被访问的区域。C++ 中有三种基本的作用域类型:
- 局部变量
- 全局变量
- 静态变量
局部变量
局部变量是在函数或代码块内部声明的变量,只能在该函数或代码块内部访问。
#include <iostream>
using namespace std;
void myFunction() {
int myNum = 10; // 局部变量
cout << "myNum inside function: " << myNum << endl;
}
int main() {
myFunction();
// cout << myNum; // 错误: myNum 在此处不可访问
return 0;
}
全局变量
全局变量是在所有函数外部声明的变量,可以在整个程序中访问。
#include <iostream>
using namespace std;
int myNum = 10; // 全局变量
void myFunction() {
cout << "myNum inside function: " << myNum << endl;
}
int main() {
cout << "myNum inside main: " << myNum << endl;
myFunction();
return 0;
}
静态变量
静态变量是在函数内部声明的变量,但使用 static 关键字声明。静态变量在函数调用结束后不会被销毁,而是保持其值直到程序结束。
#include <iostream>
using namespace std;
void myFunction() {
static int myNum = 0; // 静态变量
myNum++;
cout << "myNum is " << myNum << endl;
}
int main() {
myFunction();
myFunction();
myFunction();
return 0;
}
字面量
字面量是程序中直接使用的常量值。C++ 中有几种不同类型的字面量:
- 整数字面量
- 浮点数字面量
- 字符字面量
- 字符串字面量
- 布尔字面量
整数字面量
整数字面量可以是十进制、八进制或十六进制。
#include <iostream>
using namespace std;
int main() {
int dec = 101; // 十进制
int oct = 0145; // 八进制
int hex = 0x65; // 十六进制
cout << "Decimal: " << dec << endl;
cout << "Octal: " << oct << endl;
cout << "Hexadecimal: " << hex << endl;
return 0;
}
浮点数字面量
浮点数字面量可以是小数或指数形式。
#include <iostream>
using namespace std;
int main() {
float f1 = 3.14; // 小数形式
float f2 = 3.14e2; // 指数形式
cout << "Float 1: " << f1 << endl;
cout << "Float 2: " << f2 << endl;
return 0;
}
字符字面量
字符字面量是用单引号括起来的单个字符。
#include <iostream>
using namespace std;
int main() {
char ch = 'A';
cout << "Character: " << ch << endl;
return 0;
}
字符串字面量
字符串字面量是用双引号括起来的一系列字符。
#include <iostream>
using namespace std;
int main() {
string str = "Hello, World!";
cout << "String: " << str << endl;
return 0;
}
布尔字面量
布尔字面量只有两个值:true 和 false。
#include <iostream>
using namespace std;
int main() {
bool b1 = true;
bool b2 = false;
cout << "Boolean 1: " << b1 << endl;
cout << "Boolean 2: " << b2 << endl;
return 0;
}
修饰符类型
C++ 提供了几种修饰符类型,用于修改基本数据类型的属性。常见的修饰符包括:
signed- 有符号类型unsigned- 无符号类型short- 短类型long- 长类型
示例
#include <iostream>
using namespace std;
int main() {
short int si; // 短整型
long int li; // 长整型
signed int si_signed; // 有符号整型
unsigned int ui; // 无符号整型
si = 32767;
li = 2147483647;
si_signed = -32768;
ui = 4294967295;
cout << "Short int: " << si << endl;
cout << "Long int: " << li << endl;
cout << "Signed int: " << si_signed << endl;
cout << "Unsigned int: " << ui << endl;
return 0;
}
修饰符可以与基本数据类型组合使用,以满足不同的存储需求。
向量(Vector)
向量是 C++ 标准模板库(STL)中的一种序列容器,类似于动态数组。向量可以根据需要自动调整其大小。
向量的声明
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> myVector; // 声明一个整数向量
return 0;
}
向量的初始化
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> myVector = {1, 2, 3, 4, 5}; // 使用列表初始化
return 0;
}
向量的常用操作
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> myVector = {1, 2, 3, 4, 5};
// 添加元素
myVector.push_back(6);
// 访问元素
cout << "Element at index 0: " << myVector[0] << endl;
// 修改元素
myVector[0] = 10;
// 删除元素
myVector.pop_back();
// 获取向量大小
cout << "Vector size: " << myVector.size() << endl;
return 0;
}
遍历向量
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> myVector = {1, 2, 3, 4, 5};
// 使用范围 for 循环遍历向量
for (int i : myVector) {
cout << i << " ";
}
cout << endl;
// 使用迭代器遍历向量
for (vector<int>::iterator it = myVector.begin(); it != myVector.end(); ++it) {
cout << *it << " ";
}
cout << endl;
return 0;
}
指针
指针是 C++ 中的一个重要概念,它是一个变量,用于存储另一个变量的内存地址。
指针的声明和使用
#include <iostream>
using namespace std;
int main() {
int myNum = 10; // 整型变量
int* ptr = &myNum; // 指针变量,存储 myNum 的地址
// 输出 myNum 的值
cout << "Value of myNum: " << myNum << endl;
// 输出指针 ptr 的值(即 myNum 的地址)
cout << "Address stored in ptr: " << ptr << endl;
// 通过指针访问 myNum 的值
cout << "Value pointed to by ptr: " << *ptr << endl;
return 0;
}
指针和数组
指针可以用于遍历数组。
#include <iostream>
using namespace std;
int main() {
int myArray[5] = {10, 20, 30, 40, 50};
int* ptr = myArray; // 指针指向数组的第一个元素
for (int i = 0; i < 5; i++) {
cout << "Element " << i << ": " << *(ptr + i) << endl;
}
return 0;
}
指针和函数
指针可以作为函数参数,用于传递数组或修改变量的值。
#include <iostream>
using namespace std;
void increment(int* ptr) {
(*ptr)++;
}
int main() {
int myNum = 10;
increment(&myNum); // 传递 myNum 的地址
cout << "Value of myNum after increment: " << myNum << endl;
return 0;
}
动态内存分配
C++ 提供了 new 和 delete 操作符,用于动态分配和释放内存。
动态分配单个变量
#include <iostream>
using namespace std;
int main() {
int* ptr = new int; // 动态分配内存
*ptr = 10;
cout << "Value: " << *ptr << endl;
delete ptr; // 释放内存
return 0;
}
动态分配数组
#include <iostream>
using namespace std;
int main() {
int* ptr = new int[5]; // 动态分配数组
for (int i = 0; i < 5; i++) {
ptr[i] = i * 10;
}
for (int i = 0; i < 5; i++) {
cout << "Element " << i << ": " << ptr[i] << endl;
}
delete[] ptr; // 释放数组内存
return 0;
}
std::cout 中的 std 不是可写可不写的
动态内存分配允许在运行时根据需要分配和释放内存,提高了程序的灵活性。
在 C++ 里,std::cout 中的 std 不是可写可不写的,是否书写取决于具体情况,下面为你详细分析:
- 需要写
std的情况
std是 C++ 标准库的命名空间(namespace),cout是标准库中定义在std命名空间里用于输出的对象。在默认情况下,如果要使用cout,就必须加上std::前缀,以表明使用的是std命名空间下的cout对象。示例代码如下:
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
在上述代码中,使用 std::cout 进行输出操作,明确指定了 cout 来自 std 命名空间。
- 可以不写
std的情况
- 使用
using namespace std;语句:通过使用using namespace std;语句,能够将std命名空间中的所有名称引入到全局命名空间中,这样后续使用std命名空间里的对象时就可以省略std::前缀。示例代码如下:
#include <iostream>
using namespace std;
int main() {
cout << "Hello, World!" << endl;
return 0;
}
需要注意的是,在大型项目里使用 using namespace std; 可能会引发命名冲突问题,因为它会把 std 命名空间中的所有名称都引入到全局命名空间,所以不建议在大型项目中广泛使用。
- 使用
using std::cout;语句:如果只需要使用std命名空间中的个别名称,例如cout,可以使用using std::cout;语句将特定的名称引入到全局命名空间。示例代码如下:
#include <iostream>
using std::cout;
using std::endl;
int main() {
cout << "Hello, World!" << endl;
return 0;
}
这种方式既可以避免命名冲突,又能让代码在使用特定名称时更加简洁。

浙公网安备 33010602011771号