C++核心编程:类与对象全面解析
C++核心编程:类与对象全面解析
大家好!今天我要和大家深入探讨C++面向对象编程中最核心的概念:类与对象。👨💻 这是我们迈向高级C++开发的第一步,掌握好这部分内容,对未来学习更高级的设计模式和框架都至关重要!
📚 嵌入式开发爱好者必看:如果你对嵌入式开发感兴趣,我强烈推荐查看 FreeRTOS + STM32 学习资源库,里面包含从入门到精通的详细教程和实例代码!
📋 学习目标
- 理解类和类的成员的概念,掌握声明类的方法,以及由类定义对象的方法
- 初步掌握用类和对象编写基于对象的程序
- 学会检查和调试基于对象的程序
- 掌握类的构造函数和析构函数的定义
- 掌握对象数组、对象指针及其使用方法
- 掌握共用数据的保护方法
🔍 经典程序剖析
1. 构造函数与析构函数执行顺序分析
先阅读下面的程序,尝试预测运行结果,然后再验证:
#include <iostream>
using namespace std;
class A {
public:A() {cout << "Constructing A" << endl;}~A() {cout << "Destructing A" << endl;}
};class B {
public:B() {cout << "Constructing B" << endl;}~B() {cout << "Destructing B" << endl;}
};int main() {A a;B b;return 0;
}
代码分析:
- 这段程序展示了构造函数和析构函数的调用顺序
- 对象创建时,构造函数按照定义顺序执行(先A后B)
- 对象销毁时,析构函数按照与创建相反的顺序执行(先B后A)
- 这遵循了C++中"后进先出"的内存管理原则
🔥 实时系统编程提示:在嵌入式实时系统如FreeRTOS中,理解对象生命周期对于避免内存泄漏和系统崩溃至关重要。查看 FreeRTOS资源库 了解更多内存管理技巧!
2. 拷贝构造函数深入理解
#include<iostream>
using namespace std;class Test
{int x, y;
public:Test(int i, int j) {x = i; y = j; cout << "con\n"; }Test(Test &A) { x = A.x; y = A.y;cout << "copycon\n";}void show() {cout << "x=" << x << "\t y=" << y << endl; }
};int main()
{Test B1(2, 3); Test B2 = B1; Test B3(B1); B2.show(); B3.show();return 0;
}
代码分析:
- 这个例子展示了拷贝构造函数的两种调用方式
Test B1(2, 3)
调用普通构造函数Test B2 = B1
和Test B3(B1)
都调用拷贝构造函数- 拷贝构造函数用于创建一个新对象,该对象是现有对象的副本
- 注意拷贝构造函数的参数是引用类型,这是必须的,否则会导致无限递归
3. 对象数组与对象指针运用
#include <iostream>
using namespace std;class Sample {int x;
public:void setx(int i) {x = i; }int putx() {return x; }
};int main() {Sample *p; Sample A[3]; A[0].setx(5);A[1].setx(6);A[2].setx(7);for(int j=0; j<3; j++) { p = &A[j]; cout << p->putx() << " "; }cout << endl;return 0;
}
代码分析:
- 此程序展示了对象数组与对象指针的基本使用
Sample A[3]
创建了一个包含3个Sample对象的数组- 通过数组下标访问每个对象并设置其x成员
- 使用指针
p
依次指向数组中的每个对象 - 通过指针使用
->
运算符调用成员函数
💡 嵌入式开发技巧:在资源受限的嵌入式系统中,对象数组和指针操作的效率尤为重要。在 FreeRTOS项目 中有很多实际应用案例!
🛠️ 程序调试与优化
1. 构造函数声明修复
原代码存在问题,现已修正:
#include <iostream>
using namespace std; class A {int i;
public:A(int ii) { // 错误构造函数声明(void A→A)i = ii;}int geti() { return i;}
};int main() {A *pa; pa = new A(10); // 补充(int参数)cout << "i=" << pa->geti() << endl; return 0;
}
问题分析:
- 原代码中构造函数声明错误,使用了
void A
而非A
- 创建动态对象时缺少必要的构造函数参数
- 修正后,动态创建对象并正确初始化,输出结果为
i=10
2. 类成员访问修复
#include <iostream>
using namespace std; class base {int x, y;
public:int z;void Init(int a, int b) { setx(a);sety(b);}int getx() { return x; } int gety() { return y; } void setx(int a) { x = a; }void sety(int b) { y = b; }
}; int main() {base A, B; A.Init(76, 77); B.Init(78, 79); cout << "A.x=" << A.getx() << endl;cout << "B.x=" << B.getx() << endl;return 0;
}
问题分析:
- 原代码直接访问私有成员
x
和y
导致错误 - 修正后通过公有成员函数
getx()
访问私有成员 - 这展示了封装原则的重要性:私有成员只能通过公有接口访问
3. 解决作用域解析问题
#include <iostream>
using namespace std;class Time {
public:int hour, minute;void printTime(); void setHour(int h, int m) {hour = h; minute = m; }
}; void Time::printTime() { // 修正作用域解析cout << "hour: " << hour << "/minute: " << minute << endl; }int main() {Time aTime; aTime.setHour(5, 39); aTime.printTime(); // 未指定对象 → 补全aTime.return 0;
}
问题分析:
- 原代码中类外成员函数定义缺少作用域解析符
Time::
- 在
main()
中,成员函数调用缺少对象指定 - 修复后正确输出:
hour:5/minute:39
🔧 开发效率提升:良好的代码组织和作用域管理在复杂项目中尤为重要。查看 FreeRTOS项目 中的源码结构,学习专业的代码组织方式!
📝 程序填空题解析
1. 构造函数与访问器补全
#include<iostream>
using namespace std;
class a
{
private:int num;float f1;
public:a();a(int n, double f); // 填入参数类型 int n, double fint Getint(){return num;} // 返回类型为 intdouble Getdouble(){return f1;} // 返回类型为 double(float自动提升)
};a::a() // 类外构造函数定义
{cout<<"默认初始化"<<endl;num = 0; // 初始化整型成员f1 = 0.0; // 初始化浮点成员
}a::a(int n,double f)
{cout<<"初始化"<<endl;num=n;f1=f;
}int main()
{a x;a y(2,4.5);cout<<x.Getint()<<" "<<x.Getdouble()<<endl;cout<<y.Getint()<<" "<<y.Getdouble()<<endl;return 0 ;
}
填空解析:
- 参数构造函数声明:
a(int n, double f)
- 整型访问器返回类型:
int
- 浮点访问器返回类型:
double
- 默认构造函数定义:
a::a()
- 整型成员初始化:
num = 0
- 浮点成员初始化:
f1 = 0.0
2. 三角形计算类实现
#include <iostream> // 补全输入输出流头文件
#include <math.h>
using namespace std;
class A
{double a,b,c;
public:A (double,double,double);double fun1(); // 声明计算周长的成员函数double fun2(); // 声明计算面积的成员函数
};double A::fun1(){return a+b+c;}
A::A(double i,double j,double k)
{a=i;b=j;c=k;
}
double A::fun2()
{double d;d = (a+b+c) / 2.0;return sqrt(d*(d-a)*(d-b)*(d-c));
}int main()
{A a1(3,4,5);cout<<"三角形边长和:";cout << a1.fun1(); // 调用周长计算函数cout<<endl;cout<<"三角形面积:";cout << a1.fun2(); // 调用面积计算函数cout<<endl;return 0 ;
}
填空解析:
- 包含头文件:
#include <iostream>
- 周长计算函数声明:
double fun1();
- 面积计算函数声明:
double fun2();
- 输出周长:
cout << a1.fun1();
- 输出面积:
cout << a1.fun2();
📊 数学算法应用:像这样的几何计算在嵌入式系统中也很常见,特别是在传感器数据处理和位置计算中。FreeRTOS项目 中有许多实时数据处理的范例!
💻 实战编程挑战
1. 时钟类设计实现
#include <iostream>
#include <iomanip> // 用于格式化输出
using namespace std;class Clock {
private:int hour;int minute;int second;public:// (1) 构造函数:默认初始化00:00:00Clock() : hour(0), minute(0), second(0) {}// (1) 重载构造函数:指定时分秒Clock(int h, int m, int s) : hour(h), minute(m), second(s) {}// (2) 动态设置时间void setclock(int h, int m, int s) {hour = h;minute = m;second = s;}// (3) 格式化显示时间void showclock() {cout << setfill('0') // 不足两位补零<< setw(2) << hour << ":" << setw(2) << minute << ":" << setw(2) << second << endl;}
};int main() {Clock clock1; // 默认构造clock1.showclock(); // 输出 00:00:00clock1.setclock(12, 1, 1); // 动态设置时间clock1.showclock(); // 输出 12:01:01Clock clock2(13, 1, 1); // 指定参数构造clock2.showclock(); // 输出 13:01:01return 0;
}
实现重点:
- 使用私有数据成员保护时间数据
- 提供两种构造函数实现不同的初始化方式
- 使用
setfill
和setw
确保时间格式的标准化(两位数字,不足前补0) - 提供设置时间的公有接口,保持封装性
⏱️ 实时性提示:在实时系统中,时间管理至关重要。FreeRTOS提供了专门的时间管理函数和延时机制,详见 FreeRTOS资源库 中的时间管理部分!
2. 图书管理系统实现
#include <iostream>
#include <string>
using namespace std;class Book {
private:string bookname;double price;int number;public:// 构造函数初始化数据成员Book(string name, double p, int num) : bookname(name), price(p), number(num) {}void display() {cout << "书名:" << bookname << endl<< "价格:" << price << "元" << endl<< "库存:" << number << "本" << endl;}void borrow() {if(number > 0) {number--;cout << "借阅成功,当前库存:" << number << endl;} else {cout << "库存不足,无法借阅!" << endl;}}void restore() {number++;cout << "归还成功,当前库存:" << number << endl;}
};int main() {// 创建图书对象Book book1("C++", 23.5, 3);Book book2("Data Structure", 28.8, 7);// 操作book1cout << "----book1信息----" << endl;book1.display();book1.borrow();book1.borrow();book1.restore();// 操作book2cout << "\n----book2信息----" << endl;book2.restore(); book2.display(); return 0;
}
实现重点:
- 使用私有成员保存图书信息,体现封装原则
- 构造函数使用初始化列表高效初始化
borrow()
方法加入库存检查,防止出现负数库存- 清晰的UI设计使用户交互更直观
📚 系统设计拓展:这个简单的图书管理系统体现了面向对象编程的基本原则。在真实的嵌入式系统中,类似的资源管理更为复杂,需要考虑并发访问、资源锁定等问题。这些问题在 FreeRTOS项目 中有详细讲解和示例!
📌 总结与拓展
通过本文的学习,我们掌握了C++类与对象的核心概念:
- 类的定义与对象的创建
- 构造函数与析构函数的使用
- 拷贝构造函数的特性
- 对象数组与对象指针的操作
- 封装和数据保护
这些概念是深入理解C++的基础,也是进阶到更复杂系统设计的垫脚石。想更深入学习嵌入式开发和实时操作系统?请访问 Despacito0o的FreeRTOS学习资源库,那里有从入门到精通的全套资源!
🚀 学习建议:如果你掌握了本文的内容,推荐接下来学习C++的继承和多态特性,以及模板编程。这些高级特性将使你的代码更加灵活和强大!