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(类)是面向对象编程的关键概念,publicprivateprotected 这几个访问修饰符在类中起着至关重要的作用,它们用于控制类成员(包括数据成员和成员函数)的访问权限。以下为你详细介绍:

访问修饰符的作用

  • public:使用 public 修饰的成员可以在类的外部被自由访问。也就是说,类的对象可以直接调用这些成员。
  • privateprivate 修饰的成员只能在类的内部被访问,类的外部无法直接访问这些成员。这有助于实现数据封装和信息隐藏,提高代码的安全性和可维护性。
  • protectedprotected 修饰的成员可以在类的内部以及该类的派生类(子类)中被访问,但在类的外部不能直接访问。

代码示例

#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 部分nameage 是私有数据成员,在类的外部无法直接访问。这样做的好处是可以防止外部代码随意修改这些数据,保证数据的安全性和完整性。
  • public 部分:提供了四个公有成员函数 setNamesetAgegetNamegetAge,用于在类的外部间接访问和修改私有数据成员。通过这种方式,可以对数据的访问进行控制,例如在 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++ 中,常量通常是不可变的,但具体情况需要根据常量的类型和定义方式来详细分析,以下为你展开介绍:

  1. 字面值常量
  • 概念:字面值常量是在代码中直接写出的值,如整数、浮点数、字符、字符串等。
  • 特性:它们在程序运行期间是不可改变的。例如:
#include <iostream>
int main() {
    // 整数字面值常量
    10 = 20; // 错误,不能对字面值常量进行赋值操作
    return 0;
}

在上述代码中,试图对整数字面值常量 10 进行赋值,这会导致编译错误,因为字面值常量是不可修改的。

  1. 使用 const 关键字定义的常量
  • 基本类型常量
    • 当使用 const 关键字修饰基本数据类型(如 intdouble 等)的变量时,该变量成为常量,其值在初始化后不能被修改。
#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;
}
  1. 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 常量,其值在编译时就确定了,不能在运行时修改。

  1. 特殊情况: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 去除了 numconst 限定符,但修改 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 = &num;
    // 可以通过指针修改指向的值
    *ptr = 15; 
    std::cout << *ptr << std::endl; 
    // 以下语句会报错,因为指针本身是常量,不能再指向其他对象
    // int num2 = 20;
    // ptr = &num2; 
    return 0;
}

总结

  • 常量指针侧重于保护所指向对象的值不被修改,指针本身可以指向其他对象。
  • 指针常量侧重于固定指针的指向,一旦初始化就不能再指向其他对象,但可以修改所指向对象的值。

变量作用域

变量的作用域是程序中变量可被访问的区域。C++ 中有三种基本的作用域类型:

  1. 局部变量
  2. 全局变量
  3. 静态变量

局部变量

局部变量是在函数或代码块内部声明的变量,只能在该函数或代码块内部访问。

#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++ 中有几种不同类型的字面量:

  1. 整数字面量
  2. 浮点数字面量
  3. 字符字面量
  4. 字符串字面量
  5. 布尔字面量

整数字面量

整数字面量可以是十进制、八进制或十六进制。

#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;
}

布尔字面量

布尔字面量只有两个值:truefalse

#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++ 提供了几种修饰符类型,用于修改基本数据类型的属性。常见的修饰符包括:

  1. signed - 有符号类型
  2. unsigned - 无符号类型
  3. short - 短类型
  4. 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++ 提供了 newdelete 操作符,用于动态分配和释放内存。

动态分配单个变量

#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 不是可写可不写的,是否书写取决于具体情况,下面为你详细分析:

  1. 需要写 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 命名空间。

  1. 可以不写 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;
}

这种方式既可以避免命名冲突,又能让代码在使用特定名称时更加简洁。

posted @ 2025-03-05 03:41  学^以致用  阅读(30)  评论(0)    收藏  举报