CPP 学习笔记 语法总结
C++ 基本语法
如果之前没有接触过面向对象语言的话,在学习 C++ 之前需要先建立一些概念和思想,不然可能连基础 Hello World 程序都会疑惑,比如
std :: cout是什么意思。
在 C 语言中,全局作用域内不允许出现两个同名的函数。C++ 通过引入命名空间和类,巧妙地解决了这个问题。它们就像是给标识符(函数、变量等)加上了“姓氏”或“地址”,从而避免了命名冲突。具体到类的概念:每个类都定义了一个独立的作用域。因此,在不同的类中,完全可以定义名称、参数和返回值都完全相同的成员函数。在调用时,为了明确指出我们想调用的是哪个类中的函数,就需要使用类名来限定,格式通常为类名::函数名或通过对象来调用。::表示作用域解析运算符,用于指明空间或者类的作用域。
比如下面的例子,理解思想即可,具体语法接下来慢慢学习。
#include <iostream> |
// 定义一个 Dog(狗)类 |
class Dog { |
public: |
// Dog 类中的 speak 函数 |
void speak() { |
std::cout << "汪汪!" << std::endl; |
} |
}; |
// 定义一个 Cat(猫)类 |
class Cat { |
public: |
// Cat 类中的 speak 函数(与 Dog 类中的函数同名同参数同返回类型) |
void speak() { |
std::cout << "喵喵!" << std::endl; |
} |
}; |
int main() { |
// 创建 Dog 类和 Cat 类的对象 |
Dog myDog; |
Cat myCat; |
// 调用函数时,通过对象来区分所属的类 |
std::cout << "狗说:"; |
myDog.speak(); // 调用的是 Dog::speak() |
std::cout << "猫说:"; |
myCat.speak(); // 调用的是 Cat::speak() |
return 0; |
} |
1.1 变量
这里只介绍一下 C++ 风格字符串,因为跟 C 语言有所区别。
其实下面的例子会涉及到很多知识点,大家先有个印象,知道 C++ 字符串怎么定义初始化即可。
#include <iostream> // 基本输入输出头文件,相当于C的stdio |
#include <string> // 必须包含这个头文件 |
using namespace std; // 声明了 std 空间了之后,后面的 cout 等都不用再添加 std:: 了 |
int main() { |
// 多种初始化方式 |
string s1; // 默认初始化,空字符串 "" |
string s2 = "Hello"; // 拷贝初始化 |
string s3("World"); // 直接初始化 |
string s4(5, 'A'); // 初始化由5个'A'组成的字符串 "AAAAA" |
string s5(s2); // 用s2初始化s5,s5内容为 "Hello" |
cout << "s1: " << s1 << endl; |
cout << "s2: " << s2 << endl; |
cout << "s3: " << s3 << endl; |
cout << "s4: " << s4 << endl; |
cout << "s5: " << s5 << endl; |
return 0; |
} |
1.2 命名空间
前面有介绍过。在 C++ 项目中,同一个函数名称可能会在不同的文件中多次出现,为了解决这种命名冲突,就有了命名空间的概念。std是 C++ 标准库的命名空间,是一个庞大的工具集。
// 不使用命名空间,在使用 std 中的工具时都需要加前缀,如 |
std::cout << " " << endl; |
// 使用了命名空间之后,不用加前缀,默认是使用 std 空间中的工具 |
using namespace std; |
cout << " " << endl; |
1.3 常用头文件
<iostream> // 输入输出:cin, cout |
<string> // 字符串类 std::string |
<vector> // 向量容器(动态数组) |
<algorithm> // 排序、查找、最大最小值等算法 |
<cmath> // 数学函数:pow, sqrt, sin, 等 |
<cstdlib> // 随机数生成、内存分配等 |
<ctime> // 时间函数如 time, clock 等 |
<fstream> // 文件流:读写文件 |
1.4 输入输出操作
std::cin >> age; |
std::cout << "Age: " << age << std::endl; /* 表明std命名空间中的cout队形 */ |
int x = 10; |
class A { |
public: |
static int x; |
}; |
int A::x = 20; |
std::cout << x; // 全局的x |
std::cout << A::x; // A类中的x |
**cout **对象表述标准输出流。
**cin **对象表示标准输入流。
1.5 引用
引用就是某个变量的别名,它并不独立地占用内存,而是直接绑定到另一个已有的变量。你对引用做的任何操作,实际上就是对原变量的操作,区别于 C 语言的指针。
int a = 10; |
int &x = a; |
void addOne(int& x) { |
x += 1; |
} |
int& getRef(int& x) { |
return x; |
} |
// 遍历容器中的每一个元素 |
// vec 是一个容器,例如 std::vector<int> vec = {1, 2, 3}; |
// n 是 vec 中的一个元素。 |
// int& 表示 n 是对该元素的 引用(reference),这样你可以直接修改容器中的元素。 |
for (int& n : vec) { |
n += 1; // 修改 vec 中的元素 |
} |
1.6 常用关键字
/* 类与面向对象 */ |
class 定义类 |
struct 定义结构体(默认 public) |
public 公有访问权限 |
private 私有访问权限(类默认) |
protected 受保护访问权限 |
virtual 虚函数(支持多态) |
override 明确重写父类虚函数(C++11) |
final 禁止子类重写(C++11) |
this 当前对象指针 |
new 动态分配内存 |
delete 释放动态内存 |
friend 友元函数/类 |
explicit 禁止构造函数隐式转换 |
inline 请求内联函数 |
/* 模板和泛型编程 */ |
template 模板定义 |
typename 表示类型参数 |
constexpr 编译期常量(C++11) |
/* 类型 */ |
int* 指针类型 |
int& 引用类型 |
int[] 数组类型 |
std::string 字符串(C++类) |
new
核心功能是在堆上分配内存,并返回指向该内存的一个指针。销毁使用delete。主要功能有两个:
- 为单个对象分配内存。、
- 为数组分配内存。
// 为单个对象分配内存pointer = new TypeName;pointer = new TypeName(initial_value);// new运算符会首先向操作系统申请一块足够存储`TypeName`类型的内存。如果内存分配成功会自动调用这个对`TypeName`类型的构造函数,在这块新分配的内存中初始化一个对象。// 基于此,接下来介绍一下什么是构造函数// 对于一个类class Person,在该类型的对创建时(new)构造函数会被自动调用,为该对象赋初值。// 构造函数可重载(参数列表不同即可)// 构造函数名必须与类名一致/*** pref: 构造函数举例*/#include <iostream>#include <string>class Person {public:// 默认构造函数(无参数)Person() {name = "Unknown";age = 0;std::cout << "Default constructor called." << std::endl;}// 带参数的构造函数Person(std::string n, int a) {name = n;age = a;std::cout << "Parameterized constructor called." << std::endl;}void display() {std::cout << "Name: " << name << ", Age: " << age << std::endl;}private:std::string name;int age;};int main() {Person p1; // 调用默认构造函数Person p2("Alice", 30); // 调用带参数的构造函数p1.display();p2.display();return 0;}// 分配数组int* arr = new int[10]; // 分配并默认初始化10个intdelete[] arr; // 正确释放数组// 自动计算大小int* p = new int;
