Skip to content

Chapter 2 Using Objects

1 std::string

字符串类

#include <string>        // 头文件引入
string str;              // 定义一个空字符串变量
string str = "Hello";    // 定义变量并将其内容初始化
cin >> str;              // 读取键盘输入,遇到空格/回车/制表符停止读取
cout << str;             // 输出到标准输出

字符串的赋值操作

char cstr1[20];
char cstr2[20] = "jaguar";

string str1;
string str2 = "panther";

cstr1 = cstr2;    // illegal
str1 = str2;      // legal

字符串拼接

string str3;
str3 = str1 + str2;
str1 += str2;
str1 += "lalalala";    // 支持字符串常量拼接

常用构造函数(Ctors)

// 从 C 字符串取前 len 个字符
string (const char *cp, int len);

// 从 s2 的 pos 索引开始取到末尾
string (const string& s2, int pos);

// 从 s2 的 pos 索引取 len 个字符
string (const string& s2, int pos, int len);

子字符串(Sub-string)

// 从 pos 索引提取长度为 len 的字符串,返回新的子串
substr (int pos, int len);

字符串修改

// 重新赋值字符串(支持多种重载形式)
assign(...);

// 在指定位置插入字符/字符串(通用重载版本)
insert(...);

// 在位置 pos(从 0 开始计数)处插入字符串 s
insert(int pos, const string& s);

// 删除指定位置/范围的字符
erase(...);

// 在字符串末尾添加字符/字符串
append(...);

// 从 pos 开始、长度为 len 的子串替换为字符串 s
replace(int pos, int len, const string& s);

字符串查找

// 查找子串 s 的首次出现位置,返回索引(无则返回 string::npos)
find(const string& s);

文件 IO

#include <ifstream>     // 读文件
#include <ofstream>     // 写文件

ifstream File2("C:\\test.txt");    // Windows 路径用双反斜杠
std::string str;
File2 >> str;    // 按空格/回车分割,读取第一个单词

ofstream File1("C:\\test.txt");    
File1 << "Hello World!" << endl;
io_example.cpp
#include <iostream>     // 包含标准输入输出流库,用于控制台输出(cout、endl 等)
#include <fstream>      // 包含文件流库,用于文件读写操作(ofstream、ifstream等)
using namespace std;    // 使用标准命名空间,避免每次调用标准库时都写 std:: 前缀

int main(){
    ofstream File1("c:\\1\\2.txt");
    File1 << "Hello World!" << endl;

    ifstream File2("C:\\1\\2.txt");
    std::string str;

    File2 >> str;
    // 控制台输出第一次读取到的字符串内容
    std::cout << "str is : " << str << std::endl;

    // 继续从文件中读取下一个空白分隔的单词到 str 中
    File2 >> str;
    std::cout << "str is : " << str << std::endl;

    return 0;
}

2 Memory Model

extern 关键字
  • 作用声明全局变量(表示变量在程序的某个位置定义),而非定义
  • 用法extern int i;(仅声明,不分配内存),用于跨 .cpp 文件访问全局变量
变量类型 存储位置 特性
Global vars Global data 定义在函数外,可跨 .cpp 文件共享
Static global vars Global data 限制在当前 .cpp 文件访问,不可跨文件
Static local vars Global data 函数内定义,值在函数调用间保持,首次访问时初始化
Local vars Stack 函数内定义,函数执行完销毁
Dynamically allocated vars Heap 由 new 分配,手动 delete 销毁,生命周期由程序员控制

示例
int i;               // global vars.
static int j;        // static global vars.

void f() {
    int k;           // local vars.
    static int l;    // static local vars.
    int *p = malloc(sizeof(int));    // allocated vars.
}

3 Pointers to Objects

指针基础操作
  • &:取地址运算符,获取变量/对象的内存地址
  • *:解引用运算符,通过指针访问指向的变量/对象
  • ->:指针成员访问运算符,通过对象指针调用成员函数/属性(替代 (*p).

示例

string s = "hello";
string* ps = &s; // & 取 s 的地址,ps 为 string 类型指针
cout << (*ps).size() << endl; // 解引用后访问成员,输出 5
cout << ps->size() << endl;   // -> 直接访问成员,输出 5(推荐)

4 Dynamically Allocated Memory

动态内存分配(new/delete)

  • new:程序运行时分配堆内存,返回内存地址,仅能通过指针访问
  • delete:将堆内存归还内存池,释放后指针变为野指针,建议置空(p = nullptr;
  • 动态数组释放必须使用delete[],与new[]配对

单个变量的分配与释放

int* p = new int;         // 动态分配int类型变量,返回地址
int* p2 = new int(10);    // 动态分配并初始化
delete p;
delete p2;    // 释放堆内存

数组的分配与释放

int* parr = new int[10];    // 动态分配 int 数组,返回首元素地址
delete[] parr;    // 释放数组:必须加 [],否则仅释放首元素

指针赋值与对象赋值的区别

string s1 = "a", s2 = "b";
string* ps1 = &s1, *ps2 = &s2;
s1 = s2;      // 对象赋值:将 s2 的内容拷贝到 s1,二者独立
ps1 = ps2;    // 指针赋值:将 ps2 的地址赋给 ps1,二者指向同一个对象

newdelete 的使用规范

  • 不释放非 new分配的内存
  • 不重复释放同一块内存
  • new[] 必须对应 delete[]new 单个变量对应 delete
  • 对空指针执行 delete 是安全的

5 Reference

  • 局部或全局变量的引用定义type& refname = name;
  • 在参数列表与成员变量中的引用type& refname

赋值操作将修改原对象的值

int X = 47;
int& Y = X;             // Y 是 X 的引用,共用内存
cout << "Y = " << Y;    // prints Y = 47
Y = 18;
cout << "X = " << X;    // prints X = 18

定义时必须初始化,初始化后绑定关系不可更改

在定义时绑定
int x = 3;
int& y = x;        // 引用y在定义时绑定到变量x
const int& z = x;  // 常量引用z在定义时绑定到变量x
作为函数参数时绑定
void f(int& x);    // 函数参数声明为引用
f(y);              // 引用x在函数调用时绑定到实参y

引用的目标对象必须有实际的内存地址(不能是临时值/表达式)

void func(int &);  // 函数参数为 int 类型引用
func(i * 3);       // Warning or error!
特性 引用 指针
空值 不能为空 可为 NULL
绑定 初始化后不可改 可随时切换指向
本质 对象别名 独立变量,存储地址

使用规则

  • 无引用的引用
  • 无指向引用的指针(int&* p; 非法)
  • 无引用数组
  • 指针的引用(void f(int*& p);)合法

6 const

基本定义

C++ 中的常量默认是内部链接,编译器会尽量避免为常量分配内存空间,将常量值保存在符号表中,extern 关键字会强制为常量分配内存。

const int x = 123;  // 定义 const int 变量,必须初始化
x = 27;             // illegal:const 变量的值不可修改
x++;                // illegal

int y = x;          // ok:将 const 变量的值拷贝给非 const 变量
y = x;              // ok

const int z = y;    // ok:非 const 可赋值给 const(更安全)

编译期常量

// 值必须在定义时初始化,除非显式使用 extern 声明
const int bufsize = 1024;

// 编译器不允许修改其值
extern const int bufsize = 1024;

// 编译期常量是编译器符号表中的条目,并非真正的变量

运行期常量(Run-time constants)

// 编译期常量可用于数组定义
const int class_size = 12;
int finalGrade[class_size];   // legal

// 运行期常量在标准 C++ 中不允许用作普通数组的长度
// 但现在部分编译器(如 GCC)支持变量长度数组(VLA) 作为扩展语法
int x;
cin >> x;
const int size = x;
double classAverage[size];    // error → ok

指针与常量(Pointers and const)

  • const 紧邻数据类型时,修饰指向的内容;const 紧邻指针变量名时,修饰指针本身
常量指针
// 指针地址固定,内容可改
char * const q = s;
*q = 'c';    // OK
q++;         // ERROR
指向常量的指针
// 指向内容不可改,指针可移动
const char *p = s;
// 或:char const *p = s;
*p = 'b';    // ERROR 
最严格的常量指针
// 内容与指针都不可改
const char * const r = s;
// 或:char const *const t = s;
int i; const int ci = 3;
int * ip; ip = &i; ip = &ci; //Error
const int *cip cip = &i; cip = &ci;
*ip  = 54;  // 始终合法:ip 指向 int 类型
*cip = 54;  // 永远不合法:cip 指向 const int 类型

字符串字面量(String Literals)

  • char* s = "Hello world!"; 的本质是 const char*,不可修改内容,否则会导致未定义行为
  • 若想修改字符串,需使用数组 char s[] = "Hello world!";

类型转换(Conversions)

非常量可安全转为常量(可始终将非常量值视作常量)
void f(const int* x);  // 接收指向常量整型的指针
int a = 15;            // 定义非常量整型变量 a
f(&a);                 // OK:传入非常量变量的地址,可隐式转换为常量指针

const int b = a;       // OK:用非常量 a 初始化常量 b
f(&b);                 // OK:常量变量的地址可传入接收常量指针的函数
常量转非常量需使用显示类型转换 const_cast
b = a + 1;             // Error!

函数参数与返回值

const 值参数:函数内不可修改
// 接收常量整型参数 i
void f1(const int i) {
    i++; // Illegal:编译期错误
}
const 返回值:仅限制返回值的赋值/修改行为,不影响接收方使用
int f3() { return 1; }          // 返回整型值
const int f4() { return 1; }    // 返回常量整型值
int main() {
    const int j = f3();    // Works fine
    int k = f4();          // Works fine too
}
  • 大对象优先用指针/引用传递,加 const 防止修改