Class 与 Struct 的区别
private
访问权限和继承,适合复杂对象封装public
访问权限和继承,适合简单数据聚合类的定义方法
使用头文件和源文件分离的方式定义类,每定义一个类应当建立两个文件:
className.h
:包含类的声明、成员函数的声明className.cpp
:包含成员函数的函数体(具体实现)**示例:**Point 类的定义和使用
// Point.h class Point{ private: int x, y; public: void init(int ix, int iy); void move(int dx, int dy); }; // Point.cpp #include "point.h" #include <iostream> using namespace std; void Point::init(int ix, int iy){ x = ix; y = iy; } void Point::move(int dx, int dy){ x += dx; y += dy; } // main.cpp #include<iostream> #include "point.h" using namespace std; int main(){ Point p; p.init(2, 3); p.move(5, 5); }
作用域解析运算符 Resolver ::
Point::
来指定这个函数是属于 Point
类的,该操作符称为作用域解析运算符Class::Function
或 Class::Attribute
示例:
void S::f(){ // 定义类 S 的 f 函数 ::f(); // 调用全局作用域的 f 函数 ::a++; // 对全局作用域的 a 变量操作 a--; // 对当前作用域的 a 变量操作 }
编译单元 Computation Unit
一个 .cpp
文件就是一个编译单元,编译器会将 .cpp
文件编译成 .obj
文件,链接器会将所有的 .obj
文件链接成一个可执行文件
#include
指令会将 .h
文件的内容直接复制到 .cpp
文件中
以下是一个标准的头文件结构,里面的声明仅出现一次,这样可以避免头文件内容被多次包含,从而导致编译失败的问题
#ifndef HEADER_FLAG
#define HEADER_FLAG
// Type declaration here...
#endif // HEADER_FLAG
文件关系图
<aside> 📌
若要为函数的参数指定默认值,只能在函数声明处指定,在函数实现处不能写
</aside>
构造函数与类名 / 结构体名完全相同,可以有参数,没有返回类型
默认构造函数
构造函数的调用时机
对象被创建时,构造函数会被调用:
main
函数运行前调用构造函数示例:
struct Y{ int i; Y(int a) { i = a; } // 含参的构造函数 }; struct Z{ int i; Z(int a) { i = a; } // 含参构造函数 Z() { i = 0; } // 默认构造函数(需手动定义) }; int main(){ Y y1[2] = {Y(1), Y(2)}; // 正常工作 Y y2[3] = {Y(1), Y(2)}; // 报错,y2[2] 的创建需调用默认构造函数,而我们没有定义,编译器也没有为其创建 Z z1[3] = {Z(1), Z(2)}: // 正常工作 }
聚合初始化 Aggregate Initialization
聚合初始化允许使用花括号 {}
来直接初始化数组、结构体或类的对象,而无需显式调用构造函数
如果初始化列表中的值少于成员数量,剩余成员会被初始化为 0
、nullptr
等
使用聚合初始化进行类的对象初始化的条件:
public
)使用聚合初始化进行数组初始化
int a[5]={1,2,3,4,5};
int b[6]=5;
int c[]={1,2,3};
使用聚合初始化进行类的对象初始化
struct X{
int i;
float f;
char c;
};
X obj_1={1,2.2,'c'};
X obj_list[3]={{1,1.1,'a'},{2,3.3,'f'}};
初始化列表 Initializer List
初始化列表是初始化类成员变量的一种机制,在类的构造函数中使用,以直接初始化成员变量
初始化列表中进行的初始化是在构造函数体执行前执行的
const
成员、引用类型成员、没有默认构造函数的类类型成员,必须在初始化列表中进行初始化
初始化列表的用法
class SubClass {
public:
SubClass(int x){}
};
class MyClass {
private:
const int a;
int& ref;
SubClass obj;
public:
MyClass(int x, int& y, int z) : a(x), ref(y), obj(z)
{// 构造函数体}
};
成员变量的初始化顺序与它们在类中声明的顺序一致,而不是初始化列表中的顺序
class MyClass {
private:
int a;
int b;
public:
MyClass(int x) : b(x), a(b) {}
// 错误:a 先初始化,但 b 还未初始化
};