
在 C++ 编程世界中,类与对象是面向对象程序设计(OOP)的核心基石。从简单的数据封装到复杂的继承多态,类与对象机制为我们提供了模块化、可复用、易维护的代码组织方式。本章将全面解析类与对象的核心概念、语法规则及实战应用,带你从面向过程思维平滑过渡到面向对象思维。

面向对象程序设计(OOP)是一种以 "对象" 为中心的编程思想,其核心特点可概括为抽象、封装、继承和多态四大支柱。
抽象是从具体事物中提取核心特征而忽略次要细节的过程。在编程中,我们通过类来实现抽象,聚焦于 "是什么" 而非 "怎么做"。
例如:描述 "汽车" 时,我们关注颜色、品牌、行驶功能,而非发动机内部结构。
封装是将数据(属性)和操作数据的函数(方法)捆绑在一起,并隐藏内部实现细节,仅对外提供接口。这提高了安全性和模块化。
// 封装示例:时钟类
class Clock {
private:
// 私有数据(隐藏)
int hour, minute, second;
public:
// 公开接口(访问控制)
void setTime(int h, int m, int s) {
hour = h;
minute = m;
second = s;
}
void showTime() {
cout << hour << ":" << minute << ":" << second << endl;
}
};继承允许新类(子类)继承现有类(父类)的属性和方法,实现代码复用和扩展。
例如:"学生" 类可以继承 "人" 类的姓名、年龄属性,再添加学号、专业等特有属性。
多态指同一接口(函数名)在不同对象上有不同实现,程序运行时根据对象类型动态选择执行的代码。
例如:"动物" 类的 "发声" 方法,在 "猫" 类中实现为 "喵喵叫",在 "狗" 类中实现为 "汪汪叫"。
类是对象的模板,定义了对象的属性和行为;对象是类的实例,是具体存在的实体。
类通过class关键字定义,包含数据成员(属性)和成员函数(方法)。
// 类定义的基本格式
class 类名 {
访问控制符:
数据成员; // 属性
成员函数声明; // 方法
};
// 成员函数实现(类外)
返回类型 类名::成员函数名(参数列表) {
// 函数体
}C++ 通过访问控制符限制成员的访问权限,实现封装:
访问控制符 | 访问范围 |
|---|---|
public | 类内、类外、子类均可访问 |
private | 仅类内可访问(默认) |
protected | 类内和子类可访问,类外不可访问 |
class Person {
public: // 公开成员
string name; // 姓名
void setAge(int a); // 设置年龄的方法
private: // 私有成员
int age; // 年龄(直接访问被限制)
protected: // 保护成员
string idCard; // 身份证号(子类可访问)
}; 对象是类的实例化,通过类名 对象名创建。可通过.运算符访问对象的成员。
// 创建对象并使用
int main() {
Person p; // 创建Person类对象p
p.name = "张三"; // 访问public成员
p.setAge(20); // 调用public成员函数
// p.age = 20; // 错误:private成员不可直接访问
return 0;
}成员函数分为内联函数和非内联函数:
class Circle {
private:
double radius; // 半径
public:
// 内联函数(类内实现)
void setRadius(double r) {
radius = r;
}
// 成员函数声明(类外实现)
double getArea(); // 计算面积
double getPerimeter(); // 计算周长
};
// 类外实现成员函数(需加类名限定)
double Circle::getArea() {
return 3.14159 * radius * radius;
}
double Circle::getPerimeter() {
return 2 * 3.14159 * radius;
}下面通过完整实例展示类的定义、对象创建和成员访问:
#include <iostream>
using namespace std;
// 点类:描述平面上的点
class Point {
private:
int x; // x坐标
int y; // y坐标
public:
// 设置坐标(内联函数)
void setPoint(int x_, int y_) {
x = x_;
y = y_;
}
// 获取x坐标
int getX() {
return x;
}
// 获取y坐标
int getY() {
return y;
}
// 输出点的坐标(类外实现)
void printPoint();
};
// 类外实现成员函数
void Point::printPoint() {
cout << "(" << x << ", " << y << ")" << endl;
}
int main() {
// 创建Point对象
Point p1, p2;
// 设置坐标
p1.setPoint(3, 4);
p2.setPoint(5, 12);
// 输出坐标
cout << "p1的坐标:";
p1.printPoint();
cout << "p2的坐标:";
p2.printPoint();
// 获取坐标并计算距离
int dx = p1.getX() - p2.getX();
int dy = p1.getY() - p2.getY();
double distance = sqrt(dx*dx + dy*dy); // 需要#include <cmath>
cout << "p1与p2的距离:" << distance << endl;
return 0;
}运行结果:

构造函数和析构函数是特殊的成员函数,分别用于对象的初始化和资源清理。
构造函数在对象创建时自动调用,用于初始化对象数据成员。
#include <iostream>
#include <string>
class Student {
private:
std::string name; // 使用std::前缀
int age;
std::string id;
public:
Student(std::string n, int a, std::string i) {
name = n;
age = a;
id = i;
std::cout << "构造函数被调用" << std::endl; // 使用std::前缀
}
void showInfo() {
std::cout << "姓名:" << name << ",年龄:" << age << ",学号:" << id << std::endl;
}
};
int main() {
Student s1("张三", 18, "2023001");
s1.showInfo();
Student s2 = Student("李四", 19, "2023002");
s2.showInfo();
return 0;
}
无参数的构造函数称为默认构造函数。如果未定义任何构造函数,编译器会自动生成默认构造函数(空实现)。
#include <iostream> // 包含输入输出流头文件
#include <string> // 包含字符串头文件
using namespace std; // 使用标准命名空间
class Car {
private:
string brand;
string color;
public:
// 默认构造函数(无参数)
Car() {
brand = "未知品牌";
color = "未知颜色";
cout << "默认构造函数被调用" << endl;
}
// 带参数的构造函数
Car(string b, string c) {
brand = b;
color = c;
cout << "带参数构造函数被调用" << endl;
}
void showInfo() {
cout << "品牌:" << brand << ",颜色:" << color << endl;
}
};
int main() {
Car c1; // 调用默认构造函数
c1.showInfo();
Car c2("特斯拉", "红色"); // 调用带参数构造函数
c2.showInfo();
return 0;
}
委托构造函数允许一个构造函数调用同一类中的另一个构造函数,减少代码重复。
#include<iostream>
#include<string>
using namespace std;
class Rectangle {
private:
int length;
int width;
public:
// 目标构造函数(被委托的构造函数)
Rectangle(int l, int w) {
length = l;
width = w;
cout << "目标构造函数被调用" << endl;
}
// 委托构造函数(调用目标构造函数)
Rectangle() : Rectangle(1, 1) { // 委托给带参数的构造函数
cout << "委托构造函数(默认)被调用" << endl;
}
// 另一个委托构造函数
Rectangle(int side) : Rectangle(side, side) { // 委托创建正方形
cout << "委托构造函数(正方形)被调用" << endl;
}
int getArea() {
return length * width;
}
};
int main() {
Rectangle r1; // 调用默认委托构造函数
cout << "面积:" << r1.getArea() << endl;
Rectangle r2(5); // 调用正方形委托构造函数
cout << "面积:" << r2.getArea() << endl;
Rectangle r3(3, 4); // 调用目标构造函数
cout << "面积:" << r3.getArea() << endl;
return 0;
}运行结果:

复制构造函数用于根据已有对象创建新对象(拷贝对象),参数为同类对象的引用。
类名(const 类名& 对象名)#include<iostream>
#include<string>
using namespace std;
class Array {
private:
int* data; // 动态数组
int size;
public:
// 构造函数
Array(int s) {
size = s;
data = new int[size]; // 分配内存
cout << "构造函数:分配了" << size << "个int的内存" << endl;
}
// 复制构造函数(深拷贝)
Array(const Array& other) {
size = other.size;
data = new int[size]; // 重新分配内存
// 拷贝数据
for (int i = 0; i < size; i++) {
data[i] = other.data[i];
}
cout << "复制构造函数:深拷贝完成" << endl;
}
// 设置数组元素
void setData(int index, int value) {
if (index >= 0 && index < size) {
data[index] = value;
}
}
// 打印数组
void print() {
for (int i = 0; i < size; i++) {
cout << data[i] << " ";
}
cout << endl;
}
};
int main() {
Array arr1(3); // 创建对象
arr1.setData(0, 10);
arr1.setData(1, 20);
arr1.setData(2, 30);
cout << "arr1: ";
arr1.print();
// 使用复制构造函数创建新对象
Array arr2 = arr1; // 等价于 Array arr2(arr1);
cout << "arr2: ";
arr2.print();
return 0;
}
析构函数在对象销毁时自动调用,用于释放对象占用的资源(如动态内存、文件句柄等)。
~类名class MyString {
private:
char* str; // 动态分配的字符串
public:
// 构造函数(分配内存)
MyString(const char* s) {
int len = strlen(s);
str = new char[len + 1]; // +1 用于存储结束符'\0'
strcpy(str, s);
cout << "构造函数:创建字符串 \"" << str << "\"" << endl;
}
// 析构函数(释放内存)
~MyString() {
cout << "析构函数:释放字符串 \"" << str << "\"" << endl;
delete[] str; // 释放动态分配的内存
}
void show() {
cout << str << endl;
}
};
int main() {
{ // 代码块,用于演示对象销毁时机
MyString s1("Hello");
s1.show();
} // s1超出作用域,析构函数被调用
MyString s2("World");
s2.show();
return 0;
} // s2超出作用域,析构函数被调用运行结果:
构造函数:创建字符串 "Hello"
Hello
析构函数:释放字符串 "Hello"
构造函数:创建字符串 "World"
World
析构函数:释放字符串 "World"移动构造函数用于将临时对象(右值)的资源 "移动" 到新对象,避免不必要的拷贝,提高效率。
类名(类名&& 对象名)std::move()将左值转换为右值#include <utility> // 包含std::move
class Buffer {
private:
int* data;
int size;
public:
// 构造函数
Buffer(int s) : size(s) {
data = new int[size];
cout << "构造函数:分配" << size << "个int的内存" << endl;
}
// 移动构造函数
Buffer(Buffer&& other) noexcept { // noexcept表示不会抛出异常
// 移动资源
data = other.data;
size = other.size;
// 置空原对象指针(避免原对象析构时释放资源)
other.data = nullptr;
other.size = 0;
cout << "移动构造函数:资源移动完成" << endl;
}
// 析构函数
~Buffer() {
if (data != nullptr) {
cout << "析构函数:释放" << size << "个int的内存" << endl;
delete[] data;
} else {
cout << "析构函数:无资源可释放" << endl;
}
}
};
int main() {
// 创建临时对象(右值)
Buffer buf1(10000);
// 使用移动构造函数创建新对象(转移资源)
Buffer buf2 = std::move(buf1); // 将左值转换为右值
return 0;
}运行结果:
构造函数:分配10000个int的内存
移动构造函数:资源移动完成
析构函数:无资源可释放
析构函数:释放10000个int的内存default:显式要求编译器生成默认版本的函数delete:显式禁用某个函数(如禁止拷贝)class Example {
private:
int value;
public:
// 使用default生成默认构造函数
Example() = default;
// 带参数的构造函数
Example(int v) : value(v) {}
// 禁用复制构造函数
Example(const Example&) = delete;
// 禁用赋值运算符
Example& operator=(const Example&) = delete;
int getValue() const { return value; }
};
int main() {
Example e1; // 调用默认构造函数
Example e2(10); // 调用带参数构造函数
// Example e3 = e2; // 错误:复制构造函数已禁用
// e1 = e2; // 错误:赋值运算符已禁用
return 0;
}#include <iostream>
#include <string>
using namespace std;
class Book {
private:
string title; // 书名
string author; // 作者
int pages; // 页数
double* ratings; // 评分数组(动态分配)
int ratingCount; // 评分数量
public:
// 默认构造函数
Book() : title("未知书名"), author("未知作者"), pages(0),
ratings(NULL), ratingCount(0) { // 使用NULL替代nullptr
cout << "默认构造函数被调用" << endl;
}
// 带参数的构造函数
Book(string t, string a, int p) : title(t), author(a), pages(p),
ratings(NULL), ratingCount(0) { // 使用NULL替代nullptr
cout << "带参数构造函数被调用" << endl;
}
// 不使用委托构造函数(改为普通构造函数)
Book(string t, string a, int p, int rCount) : title(t), author(a), pages(p) {
ratingCount = rCount;
if (ratingCount > 0) {
ratings = new double[ratingCount](); // 初始化为0
} else {
ratings = NULL; // 使用NULL替代nullptr
}
cout << "带评分构造函数被调用" << endl;
}
// 复制构造函数(深拷贝)
Book(const Book& other) : title(other.title), author(other.author),
pages(other.pages), ratingCount(other.ratingCount) {
if (ratingCount > 0) {
ratings = new double[ratingCount];
// 拷贝评分数据
for (int i = 0; i < ratingCount; i++) {
ratings[i] = other.ratings[i];
}
} else {
ratings = NULL; // 使用NULL替代nullptr
}
cout << "复制构造函数被调用" << endl;
}
// 移除移动构造函数(C++11特性)
// 设置评分
void setRating(int index, double score) {
if (index >= 0 && index < ratingCount) {
ratings[index] = score;
}
}
// 显示书籍信息
void showInfo() {
cout << "书名:" << title << endl;
cout << "作者:" << author << endl;
cout << "页数:" << pages << endl;
if (ratingCount > 0) {
cout << "评分:";
for (int i = 0; i < ratingCount; i++) {
cout << ratings[i] << " ";
}
cout << endl;
}
}
// 析构函数
~Book() {
if (ratings != NULL) { // 使用NULL替代nullptr
delete[] ratings;
cout << "析构函数:释放评分数组内存" << endl;
}
cout << "析构函数:销毁书籍对象 \"" << title << "\"" << endl;
}
};
int main() {
// 测试默认构造函数
Book b1;
b1.showInfo();
cout << endl;
// 测试带参数构造函数
Book b2("C++ Primer", "Stanley Lippman", 1300);
b2.showInfo();
cout << endl;
// 测试带评分构造函数
Book b3("数据结构与算法", "严蔚敏", 400, 3); // 3个评分
b3.setRating(0, 4.5);
b3.setRating(1, 4.8);
b3.setRating(2, 4.7);
b3.showInfo();
cout << endl;
// 测试复制构造函数
Book b4 = b3; // 调用复制构造函数
cout << "b4是b3的复制:" << endl;
b4.showInfo();
cout << endl;
// 移除移动构造函数测试代码
return 0;
}
类的组合指一个类包含其他类的对象作为成员,体现 "has-a"(有一个)的关系。
当类 A 包含类 B 的对象作为成员时,称类 A 组合了类 B。创建 A 的对象时,会先调用 B 的构造函数,再调用 A 的构造函数;销毁时则相反。
// 日期类
class Date {
private:
int year, month, day;
public:
// 构造函数
Date(int y, int m, int d) : year(y), month(m), day(d) {
cout << "Date构造函数被调用:" << year << "-" << month << "-" << day << endl;
}
// 显示日期
void showDate() {
cout << year << "-" << month << "-" << day << endl;
}
// 析构函数
~Date() {
cout << "Date析构函数被调用:" << year << "-" << month << "-" << day << endl;
}
};
// 学生类(组合了Date类对象)
class Student {
private:
string name; // 姓名
Date birthday; // 生日(Date类对象,组合关系)
int score; // 成绩
public:
// 构造函数:先初始化成员对象birthday
Student(string n, int y, int m, int d, int s)
: name(n), birthday(y, m, d), score(s) { // 成员初始化列表
cout << "Student构造函数被调用:" << name << endl;
}
// 显示学生信息
void showInfo() {
cout << "姓名:" << name << endl;
cout << "生日:";
birthday.showDate();
cout << "成绩:" << score << endl;
}
// 析构函数
~Student() {
cout << "Student析构函数被调用:" << name << endl;
}
};
// 组合类的构造/析构顺序演示
int main() {
cout << "创建学生对象:" << endl;
Student s("张三", 2005, 3, 15, 90);
s.showInfo();
return 0;
}运行结果:
创建学生对象:
Date构造函数被调用:2005-3-15
Student构造函数被调用:张三
姓名:张三
生日:2005-3-15
成绩:90
Student析构函数被调用:张三
Date析构函数被调用:2005-3-15当两个类相互引用时,需使用前向引用声明(forward declaration)告知编译器类的存在。
// 前向引用声明:告知编译器Teacher类存在
class Teacher;
// 学生类:引用Teacher类
class Student {
private:
string name;
Teacher* advisor; // 只能声明为指针或引用
public:
Student(string n) : name(n) {}
// 设置导师
void setAdvisor(Teacher* t);
void showAdvisor();
};
// 教师类:引用Student类
class Teacher {
private:
string name;
Student* student; // 学生
public:
Teacher(string n) : name(n) {}
void setStudent(Student* s) {
student = s;
}
string getName() const {
return name;
}
};
// 实现Student类的成员函数(此时Teacher类已完整定义)
void Student::setAdvisor(Teacher* t) {
advisor = t;
t->setStudent(this); // 相互关联
}
void Student::showAdvisor() {
cout << name << "的导师是:" << advisor->getName() << endl;
}
int main() {
Student s("李四");
Teacher t("王教授");
s.setAdvisor(&t); // 建立关联
s.showAdvisor();
return 0;
}UML(统一建模语言)是用于软件设计的标准化图形语言,类图是最常用的 UML 图之一。
UML 提供了一套图形符号用于可视化软件系统的结构和行为,包括类图、用例图、时序图等。类图用于描述类的结构及类之间的关系。
UML 类图用矩形表示类,分为三部分:类名、属性、方法。

符号说明:
+:public 成员-:private 成员#:protected 成员--表示关联,<-表示继承 结构体(struct)与类类似,但默认访问权限为public(类默认是private)。通常用于存储数据集合,类用于封装数据和行为。
// 结构体示例:点坐标
struct Point {
int x; // 默认public
int y; // 默认public
// 结构体也可以有成员函数
Point(int x_, int y_) : x(x_), y(y_) {}
void print() {
cout << "(" << x << ", " << y << ")" << endl;
}
};
// 结构体与类的区别演示
class PointClass {
int x; // 默认private
int y; // 默认private
public: // 需要显式声明public
PointClass(int x_, int y_) : x(x_), y(y_) {}
void print() {
cout << "(" << x << ", " << y << ")" << endl;
}
};
int main() {
// 结构体使用
Point p1(3, 4);
p1.x = 5; // 直接访问public成员
p1.print(); // (5, 4)
// 类使用
PointClass p2(6, 7);
// p2.x = 8; // 错误:x是private成员
p2.print(); // (6, 7)
return 0;
} 联合体(union)所有成员共享同一块内存空间,同一时间只能存储一个成员的值,节省内存。
#include <cstring> // 用于strcpy
// 联合体示例:存储不同类型的数据,但只能同时使用一种
union Data {
int i; // 整数
float f; // 浮点数
char str[20]; // 字符串
};
int main() {
Data d;
d.i = 100; // 存储整数
cout << "整数值:" << d.i << endl;
d.f = 3.14f; // 存储浮点数(覆盖之前的整数)
cout << "浮点数值:" << d.f << endl;
strcpy(d.str, "Hello Union"); // 存储字符串(覆盖之前的浮点数)
cout << "字符串值:" << d.str << endl;
// 注意:此时访问i或f会得到无意义的值
cout << "此时访问整数i:" << d.i << "(无意义)" << endl;
// 联合体大小为最大成员的大小
cout << "Data联合体大小:" << sizeof(Data) << "字节" << endl;
return 0;
}枚举类型用于定义命名的整数常量集合,提高代码可读性。
// 传统枚举
enum Weekday {
Monday, // 0
Tuesday, // 1
Wednesday, // 2
Thursday, // 3
Friday, // 4
Saturday, // 5
Sunday // 6
};
// 带作用域的枚举(C++11):避免命名冲突
enum class Color {
Red, // 0
Green, // 1
Blue, // 2
Yellow // 3
};
// 指定枚举值
enum Month {
January = 1,
February, // 2
March, // 3
// ... 其他月份
December = 12
};
int main() {
// 使用传统枚举
Weekday today = Wednesday;
cout << "今天是星期" << today + 1 << endl; // Wednesday是2,输出3
// 使用带作用域的枚举(必须加作用域)
Color favorite = Color::Blue;
if (favorite == Color::Blue) {
cout << "我最喜欢的颜色是蓝色" << endl;
}
// 使用指定值的枚举
Month currentMonth = January;
cout << "当前月份是:" << currentMonth << endl; // 输出1
return 0;
}设计BankAccount类实现个人银行账户管理,包含以下功能:
#include <iostream>
#include <string>
#include <vector>
#include <iomanip> // 用于格式化输出
#include <ctime> // 用于记录交易时间
#include <sstream> // 用于数值转字符串(C++98方式)
using namespace std;
// 辅助函数:将double转换为string(C++98兼容)
string doubleToString(double value) {
stringstream ss;
ss << value;
return ss.str();
}
// 银行账户类
class BankAccount {
private:
string accountId; // 账号
string name; // 账户姓名
double balance; // 账户余额
vector<string> transactionHistory; // 交易历史记录
// 获取当前时间字符串(辅助函数)
string getCurrentTime() {
time_t now = time(0);
char* dt = ctime(&now);
return string(dt); // 转换为string并返回
}
public:
// 构造函数:初始化账户
BankAccount(string id, string n, double initial = 0.0)
: accountId(id), name(n), balance(initial) {
// 记录开户信息(使用自定义的doubleToString替代to_string)
if (initial > 0) {
transactionHistory.push_back(getCurrentTime() + " 开户存款:" + doubleToString(initial) + "元");
} else {
transactionHistory.push_back(getCurrentTime() + " 账户开户,初始余额:0元");
}
}
// 存款
void deposit(double amount) {
if (amount > 0) {
balance += amount;
// 使用自定义的doubleToString替代to_string
transactionHistory.push_back(getCurrentTime() + " 存款:" + doubleToString(amount) + "元,余额:" + doubleToString(balance) + "元");
cout << "存款成功!当前余额:" << balance << "元" << endl;
} else {
cout << "存款金额必须大于0!" << endl;
}
}
// 取款
bool withdraw(double amount) {
if (amount <= 0) {
cout << "取款金额必须大于0!" << endl;
return false;
}
if (amount > balance) {
cout << "余额不足!当前余额:" << balance << "元" << endl;
return false;
}
balance -= amount;
// 使用自定义的doubleToString替代to_string
transactionHistory.push_back(getCurrentTime() + " 取款:" + doubleToString(amount) + "元,余额:" + doubleToString(balance) + "元");
cout << "取款成功!当前余额:" << balance << "元" << endl;
return true;
}
// 查询余额
double getBalance() const {
return balance;
}
// 显示账户基本信息
void showInfo() const {
cout << "\n===== 账户信息 =====" << endl;
cout << "账号:" << accountId << endl;
cout << "姓名:" << name << endl;
cout << "当前余额:" << fixed << setprecision(2) << balance << "元" << endl;
cout << "====================" << endl << endl;
}
// 显示交易历史(使用C++98的迭代器循环替代范围for循环)
void showHistory() const {
cout << "\n===== 交易历史 =====" << endl;
// 用迭代器循环替代范围for循环
for (vector<string>::const_iterator it = transactionHistory.begin();
it != transactionHistory.end(); ++it) {
cout << *it;
}
cout << "====================" << endl << endl;
}
};
// 主函数:实现用户交互
int main() {
// 创建银行账户
string id, name;
double initial;
cout << "===== 欢迎使用个人银行账户管理系统 =====" << endl;
cout << "请输入账号:";
cin >> id;
cin.ignore(); // 忽略输入缓冲区的换行符
cout << "请输入账户姓名:";
getline(cin, name);
cout << "请输入初始存款金额(0表示不存款):";
cin >> initial;
// 创建账户对象
BankAccount account(id, name, initial);
cout << "账户创建成功!" << endl;
// 菜单循环
int choice;
double amount;
do {
cout << "\n===== 操作菜单 =====" << endl;
cout << "1. 存款" << endl;
cout << "2. 取款" << endl;
cout << "3. 查询余额" << endl;
cout << "4. 显示账户信息" << endl;
cout << "5. 查看交易历史" << endl;
cout << "0. 退出系统" << endl;
cout << "请选择操作:";
cin >> choice;
switch (choice) {
case 1: // 存款
cout << "请输入存款金额:";
cin >> amount;
account.deposit(amount);
break;
case 2: // 取款
cout << "请输入取款金额:";
cin >> amount;
account.withdraw(amount);
break;
case 3: // 查询余额
cout << "当前账户余额:" << fixed << setprecision(2)
<< account.getBalance() << "元" << endl;
break;
case 4: // 显示账户信息
account.showInfo();
break;
case 5: // 查看交易历史
account.showHistory();
break;
case 0: // 退出
cout << "感谢使用,再见!" << endl;
break;
default:
cout << "无效的选择,请重新输入!" << endl;
}
} while (choice != 0);
return 0;
}
程序说明:
BankAccount类封装了账户的核心功能,通过私有成员保护账户数据vector存储交易历史,每次操作都记录时间和金额fixed和setprecision确保金额显示两位小数位域(bit field)允许将数据成员存储在指定的二进制位数中,节省内存空间。
#include <iostream>
using namespace std;
// 使用位域存储状态信息
struct Flags {
// 每个成员后面的数字表示占用的位数
unsigned int isActive : 1; // 1位:0或1
unsigned int mode : 2; // 2位:0~3
unsigned int priority : 3; // 3位:0~7
unsigned int reserved : 26; // 26位:预留(总32位)
};
int main() {
Flags f;
// 设置位域值
f.isActive = 1; // 激活状态
f.mode = 2; // 模式2
f.priority = 5; // 优先级5
cout << "isActive: " << f.isActive << endl;
cout << "mode: " << f.mode << endl;
cout << "priority: " << f.priority << endl;
// 位域结构体大小
cout << "Flags结构体大小:" << sizeof(f) << "字节" << endl; // 输出4字节(32位)
return 0;
} 构造函数可以定义从其他类型到当前类类型的隐式转换,使用explicit关键字可禁止隐式转换。
class Distance {
private:
double meters; // 以米为单位存储距离
public:
// 普通构造函数
Distance(double m) : meters(m) {}
// explicit构造函数:禁止隐式转换
explicit Distance(int cm) {
meters = cm / 100.0; // 厘米转米
}
double getMeters() const { return meters; }
double getCentimeters() const { return meters * 100; }
};
// 接受Distance类型参数的函数
void printDistance(Distance d) {
cout << "距离:" << d.getMeters() << "米 ("
<< d.getCentimeters() << "厘米)" << endl;
}
int main() {
// 隐式转换:double -> Distance(允许,因为构造函数未加explicit)
Distance d1 = 10.5; // 等价于 Distance d1(10.5)
printDistance(20.3); // 隐式转换:20.3 -> Distance
// 下面代码会报错,因为Distance(int)是explicit的
// Distance d2 = 1500; // 错误:禁止int到Distance的隐式转换
// printDistance(2000); // 错误:禁止隐式转换
// 显式转换是允许的
Distance d3 = Distance(1500); // 显式构造
printDistance(Distance(2000)); // 显式转换
return 0;
}对象作为参数或返回值时有三种传递方式:值传递、引用传递、指针传递。
#include <iostream>
using namespace std;
class MyClass {
private:
int value;
public:
// 构造函数
MyClass(int v) : value(v) {
cout << "构造函数:value = " << value << endl;
}
// 复制构造函数
MyClass(const MyClass& other) : value(other.value) {
cout << "复制构造函数:value = " << value << endl;
}
// 析构函数
~MyClass() {
cout << "析构函数:value = " << value << endl;
}
void setValue(int v) { value = v; }
int getValue() const { return value; }
};
// 1. 值传递:会调用复制构造函数
void passByValue(MyClass obj) {
obj.setValue(20);
cout << "值传递函数内:" << obj.getValue() << endl;
}
// 2. 引用传递:不会调用复制构造函数
void passByReference(MyClass& obj) {
obj.setValue(30);
cout << "引用传递函数内:" << obj.getValue() << endl;
}
// 3. 指针传递:不会调用复制构造函数
void passByPointer(MyClass* obj) {
obj->setValue(40);
cout << "指针传递函数内:" << obj->getValue() << endl;
}
// 返回值传递:会调用复制构造函数(编译器可能优化)
MyClass returnByValue() {
MyClass temp(50);
return temp; // 返回临时对象
}
int main() {
MyClass obj(10);
cout << "调用函数前:" << obj.getValue() << endl;
// 测试值传递
passByValue(obj);
cout << "值传递后:" << obj.getValue() << endl; // 仍为10(修改的是副本)
// 测试引用传递
passByReference(obj);
cout << "引用传递后:" << obj.getValue() << endl; // 变为30(修改的是原对象)
// 测试指针传递
passByPointer(&obj);
cout << "指针传递后:" << obj.getValue() << endl; // 变为40(修改的是原对象)
// 测试返回值传递
MyClass obj2 = returnByValue();
cout << "返回值传递后:" << obj2.getValue() << endl; // 50
return 0;
}本章深入讲解了 C++ 面向对象程序设计的核心概念 —— 类与对象,主要内容包括:
.使用。掌握类与对象是学好 C++ 的关键,它们为后续学习继承、多态、模板等高级特性奠定了基础。建议多编写代码实践,深入理解面向对象的思维方式。