类与对象
(1)第一部分:类基础
【关系说明】
-
类:同类对象的抽象模板(设计蓝图)
-
对象:类的具体实例(根据蓝图建造的房子)
【访问控制】
class Clock {
private: // 仅类内可访问(默认)
int hour, minute, second;
protected: // 类内和派生类可访问
string model;
public: // 完全开放访问
void setTime(int h, int m, int s);
void display();
};
【对象定义与访问】
Clock myClock; // 创建对象
myClock.setTime(10,30,0); // 正确:访问public成员
// myClock.hour = 10; // 错误:private成员外部不可访问
【成员函数实现】
-
类外实现(推荐方式):
// 函数原型在类内声明 void Clock::setTime(int h, int m, int s) { hour = h; // 直接访问private成员 minute = m; second = s; }
-
内联函数实现(两种方式):
// 方式1:类内直接定义(自动inline) class Clock { public: void display() { // 自动成为内联函数 cout << hour << ":" << minute << ":" << second; } }; // 方式2:显式声明inline inline void Clock::reset() { hour = minute = second = 0; }
(2)第二部分:高级特性
【1. 构造函数】
【作用】 对象初始化(类似给新建房屋通水电)
【核心特性】 -
函数名=类名,无返回值
-
未定义时编译器生成默认空构造函数
-
自定义后默认构造函数失效(可通过重载恢复)
class Student { private: string name; int age; public: // 自定义构造函数 Student(string n, int a) : name(n), age(a) {} // 恢复默认构造(两种写法) Student() = default; // C++11推荐写法 // Student() {} // 传统写法 }; // 使用示例 Student s1("Alice", 18); // 调用自定义构造 Student s2; // 调用默认构造
【委托构造函数】
class Point { int x, y; public: Point() : Point(0,0) {} // 委托给双参构造 Point(int a) : Point(a,0) {} Point(int a, int b) : x(a), y(b) {} };
【2. 复制构造函数】
【形式】类名(const 类名& 源对象)
【调用场景】class Book { public: Book(const Book& other) { // 自定义复制构造 cout << "复制构造被调用!"; } }; // 场景1:对象初始化 Book book1; Book book2 = book1; // 触发复制构造 // 场景2:函数传参 void readBook(Book b) {...} readBook(book1); // 传参时触发复制构造
【禁用复制构造】
Book(const Book&) = delete; // 禁止复制
【3. 析构函数】
【作用】 对象销毁时自动调用(类似房屋拆除) -
class FileHandler { FILE* file; public: FileHandler(const char* filename) { file = fopen(filename, "r"); } ~FileHandler() { if(file) fclose(file); // 确保资源释放 } };
类的组合
1. 基本概念
核心特点:类中包含其他类的对象作为成员
class Engine { // 组件类
public:
Engine(string type) : type(type) {
cout << "Engine构造: " << type << endl;
}
private:
string type;
};
class Car { // 组合类
Engine engine; // 对象成员
int wheels;
public:
Car(string engType, int w)
: engine(engType), wheels(w) { // 必须初始化对象成员
cout << "Car构造完成" << endl;
}
};
2. 构造函数设计原则
【重要原则】
-
必须通过初始化列表对对象成员进行构造
-
基本类型成员也可通过初始化列表赋值
// 正确写法(通过初始化列表构造) Car(string engType, int w) : engine(engType), wheels(w) {} // 错误写法(对象成员不能在函数体内构造) Car(string engType, int w) { engine = Engine(engType); // 错误!此处会先调用默认构造 wheels = w; }
3. 初始化次序【重点】
严格遵循两个规则:
-
声明顺序:按照成员在类中的声明顺序初始化(与初始化列表顺序无关)
-
构造阶段:
-
先执行所有成员的初始化(对象成员调用构造函数,基本类型赋值)
-
最后执行构造函数体内的代码
class Computer { CPU cpu; // 第1个声明 Memory mem; // 第2个声明 public: // 初始化列表顺序不影响实际构造顺序 Computer() : mem(8), cpu("i7") {} // 实际构造顺序:cpu → mem };
验证示例:
class A { public: A() { cout << "A构造" << endl; } }; class B { public: B() { cout << "B构造" << endl; } }; class Test { A a; // 先声明 B b; // 后声明 public: Test() : b(), a() { // 初始化列表顺序故意颠倒 cout << "Test构造体" << endl; } }; /* 输出结果: A构造 B构造 Test构造体 */
4. 组合类的复制构造函数
【关键点】 需要显式处理对象成员的拷贝
class Person { Heart heart; // 心脏对象成员 public: // 自定义复制构造 Person(const Person& other) : heart(other.heart) { // 其他成员的复制... } // 默认复制构造等价于: // Person(const Person& other) : heart(other.heart) {} };
深度拷贝示例:
class Wheel { int* pressure; // 指针成员 public: Wheel(int p) : pressure(new int(p)) {} // 自定义复制构造(深拷贝) Wheel(const Wheel& other) : pressure(new int(*other.pressure)) {} ~Wheel() { delete pressure; } }; class Bicycle { Wheel frontWheel; Wheel backWheel; public: // 组合类的复制构造会自动调用成员对象的复制构造 Bicycle(const Bicycle& other) : frontWheel(other.frontWheel), // 调用Wheel的复制构造 backWheel(other.backWheel) {} };
5. 前向引用声明
应用场景:两个类互相包含对方指针/引用时
// 前向声明(只能声明不能实例化) class ClassB; class ClassA { public: void interact(ClassB& b); // 只能使用引用/指针 private: ClassB* bPtr; }; class ClassB { // 实际定义 public: void connect(ClassA& a); };
使用限制:
-
不能创建该类的对象
-
不能访问成员细节(直到类被完整定义)
class ClassC; // 前向声明 void func() { // ClassC c; // 错误!不完整类型 // cout << sizeof(ClassC); // 错误!不知道大小 ClassC* ptr; // 允许声明指针 }
重点标注说明
-
【必须掌握】构造函数/析构函数的定义与使用场景
-
【易错点】组合类的成员初始化顺序取决于声明顺序
-
【重要区别】复制构造与默认构造的触发条件
-
【常用技巧】通过
=default
和=delete
控制特殊函数
-
重点练习建议
-
实现一个
BankAccount
类:-
private数据:账号、余额
-
public方法:存款、取款、查询
-
构造函数:初始化账号和初始余额
-
-
实现组合类
Car
:-
包含
Engine
类和Wheel
类对象成员 -
测试构造函数的执行顺序
-
简略版本:
类与对象
(1)第一部分:
关系:类是同一类对象的抽象,对象是类的某一特定实体
public、private、protected
对象定义的语法:
类名 对象名 例如:Clock myClock 在类外,使用对象名.成语名来访问public
使用void Clock::setTime
public中的一组函数是共享private中的成员数据的,不需要有返回值
类的成员函数:
一般是在类中给出函数的原型声明,在类外给出函数体的实现,并在函数名前使用类名来加以限定
也可在类中直接给出函数体,形成内联成员函数(不要有循环语句和switch语句) 使用inline
(2)第二部分
1.构造函数:定义对象时对其进行初始化
形式:函数名与类名相同。不能定义返回值类型、也不能有返回值,即return语句
未写时自动生成一个默认构造函数:参数表为空的构造函数,全部参数都有默认值的构造函数
在写了构造函数后,可直接写出初始化时的对象
当自己写了构造函数时,编译不会对其进行默认构造函数,但可以函数重载,再写一个默认构造函数
"=default"
若自己已经写了,但是还是想编译器生成构造函数,可以写一个构造函数=default
Clock()=default
委托构造函数:使用类中的其他构造函数来构造函数、
复制构造函数:用已经存在的对象来初始化新的构造函数
形式:类名(const 类名 &对象名);
"=delete":提示编译器不要生成默认复制构造函数
复制构造函数被调用两种情况:
1.定义一个对象,以本类另一个对象作为初始值,发生复制构造;
2.函数的形参时类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制构造
左值和右值
左值引用&,右值引用&&
move函数
移动构造函数 //了解即可
析构函数:不存在参数
形式:~Point()
类的组合:
类中的成员是另一个类的 对象
类组合的构造函数设计:
原则:不仅对本类的基本类型成员初始化,也要对对象成员初始化
形式:生成出来
构造组合类对象时的初始化次序
首先对构造函数初始化列表中列出的成员(包括基本类型成员和对象成员
进行初始化,初始化次序是成员在类体中定义的次序。
。成员对象构造函数调用顺序:按对象成员的声明顺序,先声明者先构造。
初始化列表中未出现的成员对象,调用用默认构造函数(即无形参的)初始化
处理完初始化列表之后,再执行构造函数的函数体。
组合类的复制构造函数:。。
当两个类相互引用时,使用前向引用声明
使用时只能使用被声明的符号
但若需要知道细节的时候,就不能使用向前引用声明