- 实验题目
我公司为仪器生产企业,目前生产摄像机和行车记录仪两种产品,分别销售给用户。
摄像机包含摄像、图像质量设定、编码算法等属性。
将摄像机增加相应芯片(具有操作菜单、自动拍摄、车速传感器、源代码等功能)后,形成一个行车记录仪。
要求:
设计摄像机类,并请根据下列不同的功能要求:
(一)采用不同的继承方式,设计行车记录仪类,并添加测试代码,体验不同继承方式下的成员访问属性。(类设计时可根据需要自行添加数据成员和其他成员函数。)
(1) 行车记录仪的芯片可以使用摄像机的摄像、图像质量设定功能。
行车记录仪用户可以操作行车记录仪的操作菜单和摄像机的摄像功能。
(2)行车记录仪的芯片可以使用摄像机的拍摄、图像质量设定功能。
行车记录仪用户仅仅可以操作行车记录仪的操作菜单。
(3) 行车记录仪的芯片可以使用摄像机的拍摄、图像质量设定功能。
行车记录仪用户仅仅可以操作行车记录仪的操作菜单
同时其他公司购买行车记录仪,因该公司也用于销售,不得泄露其全部内容
- 采用组合方式设计行车记录仪类,体验继承和组合的关系:
(1)分别为继承和组合方式下为各类添加构造函数、析构函数,增加相应测试代码,体验对象的初始化和构造顺序。
(2)将摄像机类和行车记录仪类功能相近的函数(如拍摄、编码等功能函数)设为同名函数,增加相应测试代码,体验同名函数覆盖。
(3)为我公司建立一个多态的产品类层次结构,测试时,创建一个基类指针的容器,通过基类指针调用虚函数,体验多态。
- 解决方案
1.1
1.定义基类:首先定义了Camera类,作为基类,它包含了摄像机的基本功能,如captureImage和setImageQuality。
2.设置访问权限:在Camera类中,定义了公有、保护和私有成员。公有成员可以在任何地方被访问;保护成员可以在基类和派生类中被访问;私有成员只能在基类内部被访问。
3.设计派生类:DashCam类继承自Camera类,通过公有继承,它可以访问基类的公有和保护成员。在DashCam类中,实现了行车记录仪特有的功能,如operateMenu和autoCapture。
测试代码:在main函数中,创建了一个DashCam对象,并测试了继承自Camera的公有方法和DashCam特有的方法。
1.2
1.继承:行车记录仪类(DashCam)继承自摄像机类(Camera),以便复用摄像机的功能。
2.访问控制:通过公有(public)、保护(protected)和私有(private)关键字来控制成员函数的访问权限。
3.公有继承:行车记录仪公有继承摄像机,使得其可以访问摄像机的公有和保护成员。
4.测试:编写测试代码来验证行车记录仪类可以正确访问和使用摄像机的公有功能,但不能直接访问其保护或私有成员。
1.3
1.定义摄像机类:包括摄像、图像质量设定等功能的实现。
2.定义行车记录仪类:选择私有继承自摄像机类,以确保外部不能直接访问摄像机类的成员。
实现行车记录仪特有的功能:如操作菜单、车速传感器等。
3.提供必要的公有接口:在行车记录仪类中提供操作菜单和自动拍摄等功能的公有接口。
4.编写测试代码:验证行车记录仪类可以正确访问和使用摄像机类的功能,同时外部不能直接访问摄像机类的其他成员。
注意:在实际应用中,如果行车记录仪需要向其他公司出售但不得泄露全部内容,可能需要考虑更复杂的封装和接口设计策略,如使用接口(Interface)或抽象类(Abstract Class)来定义公共的、受限的接口,以及使用友元类或函数来允许受信任的代码访问私有或保护成员。
2.1
1.定义摄像机类:包含摄像、图像质量设定等方法,并实现构造函数和析构函数。
2.定义芯片类:包含操作菜单、自动拍摄等方法,并实现构造函数和析构函数。
3.定义继承方式的行车记录仪类:继承自摄像机类,但通常不推荐使用继承来表示这种“有”关系。
4.定义组合方式的行车记录仪类:包含摄像机和芯片的对象作为私有成员,并提供方法来使用它们。实现构造函数和析构函数。
5.编写测试代码:分别测试继承方式和组合方式的行车记录仪类,体验对象的初始化和构造顺序。注意组合方式中对象的构造顺序(先构造摄像机,再构造芯片,最后构造行车记录仪本身)。
6.观察输出:注意构造函数和析构函数的调用顺序,理解对象的生命周期和内存管理。
2.2
1.抽象与封装:首先,我们将摄像机和行车记录仪的功能抽象为两个类(Camera和DashboardCamera)。每个类封装了它们各自特有的属性和方法。
2.继承:DashboardCamera类通过继承Camera类,获得了摄像机的所有功能,包括拍摄、图像质量设定和编码算法等。
3.组合:DashboardCamera类不仅继承了Camera类,还通过组合的方式添加了一个DashboardCameraChip对象,该对象封装了行车记录仪特有的功能(如操作菜单、自动拍摄等)。
4.同名函数覆盖:在DashboardCamera类中,我们覆盖了Camera类的shoot方法。这样,当调用DashboardCamera对象的shoot方法时,会先执行DashboardCamera类中定义的逻辑(自动拍摄),然后再执行Camera类中定义的逻辑(摄像)。
5.测试:编写测试代码,验证Camera类和DashboardCamera类的功能是否按预期工作,包括覆盖的函数和新增的功能。
2.3
1.定义基类:定义摄像机类Camera,包含基本的属性和方法(如录制)。
2.定义组合类:定义摄像机芯片类CameraChip,包含行车记录仪需要的额外功能。
3.定义派生类:定义行车记录仪类DashCam,继承自摄像机类并组合一个摄像机芯片对象。根据需要重写基类的方法。
4.使用基类指针容器:创建一个存储基类指针(或智能指针)的容器,并将不同类型的摄像机对象添加到容器中。
5.通过基类指针调用虚函数:遍历容器,并通过基类指针调用虚函数。由于多态,会调用相应对象的实际实现。
- 程序清单
1.1
#include <iostream>
#include <string>
// 摄像机类
class Camera {
public:
// 公有成员
void captureImage() {
std::cout << "Capturing image..." << std::endl;
}
void setImageQuality(int quality) {
// 假设这里设置图像质量的实现...
std::cout << "Setting image quality to " << quality << std::endl;
}
protected:
// 保护成员(行车记录仪可以访问)
// 假设有编码算法等
void encodeAlgorithm() {
std::cout << "Encoding algorithm is running..." << std::endl;
}
private:
// 私有成员(仅摄像机类可以访问)
// 假设有摄像硬件的初始化等
void initializeHardware() {
std::cout << "Initializing camera hardware..." << std::endl;
}
};
// 行车记录仪类(公有继承)
class DashCam : public Camera {
public:
void operateMenu() {
std::cout << "Operating menu..." << std::endl;
}
// 继承自Camera的公有成员可以直接访问
void startRecording() {
captureImage(); // 调用父类Camera的公有方法
encodeAlgorithm(); // 调用父类Camera的保护方法
// initializeHardware(); // 不可访问,因为是私有方法
}
// 假设行车记录仪特有的成员
void autoCapture() {
std::cout << "Auto capturing image..." << std::endl;
}
// 假设还有车速传感器和源代码等功能...
};
// 测试代码
int main() {
DashCam myDashCam;
myDashCam.captureImage(); // 调用继承的公有方法
myDashCam.setImageQuality(1080); // 设置图像质量
myDashCam.operateMenu(); // 使用行车记录仪特有的方法
myDashCam.startRecording(); // 调用继承和特有的方法
return 0;
}
1.2
#include <iostream>
#include <string>
// 摄像机类
class Camera {
public:
Camera() {}
// 摄像功能
void capture() {
std::cout << "Capturing image..." << std::endl;
}
// 图像质量设定
void setImageQuality(int quality) {
// 假设这里会设置图像质量
std::cout << "Setting image quality to " << quality << std::endl;
}
protected:
// 编码算法(保护继承)
void encode() {
std::cout << "Encoding image..." << std::endl;
}
private:
};
// 行车记录仪类,公有继承自摄像机类
class DashCam : public Camera {
public:
DashCam() {}
// 操作菜单(公有成员)
void operateMenu() {
std::cout << "Operating menu..." << std::endl;
}
// 自动拍摄(使用摄像机的拍摄功能)
void autoCapture() {
capture(); // 摄像机类中的公有方法
}
// 车速传感器(假设是一个功能)
void speedSensor() {
std::cout << "Measuring speed..." << std::endl;
}
// 注意:编码算法是保护的,所以DashCam可以访问但不能直接公开给用户
private:
// 私有成员,比如芯片的一些私有设置等
};
// 测试代码
int main() {
DashCam dashCam;
dashCam.operateMenu(); // 用户可以操作菜单
dashCam.autoCapture(); // 使用摄像机的拍摄功能
return 0;
}
1.3
#include <iostream>
#include <string>
// 摄像机类
class Camera {
public:
Camera() {}
// 摄像功能
void capture() {
std::cout << "Capturing image..." << std::endl;
}
// 图像质量设定
void setImageQuality(int quality) {
// 假设这里会设置图像质量
std::cout << "Setting image quality to " << quality << std::endl;
}
protected:
// 编码算法(保护继承)
void encode() {
std::cout << "Encoding image..." << std::endl;
}
private:
};
// 行车记录仪类,公有继承自摄像机类
class DashCam : public Camera {
public:
DashCam() {}
// 操作菜单(公有成员)
void operateMenu() {
std::cout << "Operating menu..." << std::endl;
}
// 自动拍摄(使用摄像机的拍摄功能)
void autoCapture() {
capture(); // 摄像机类中的公有方法
}
// 车速传感器(假设是一个功能)
void speedSensor() {
std::cout << "Measuring speed..." << std::endl;
}
// 注意:编码算法是保护的,所以DashCam可以访问但不能直接公开给用户
private:
// 私有成员,比如芯片的一些私有设置等
};
// 测试代码
int main() {
DashCam dashCam;
dashCam.operateMenu(); // 用户可以操作菜单
dashCam.autoCapture(); // 使用摄像机的拍摄功能
return 0;
}
2.1
#include <iostream>
// 摄像机类
class Camera {
public:
Camera() {
std::cout << "Camera constructor called." << std::endl;
}
~Camera() {
std::cout << "Camera destructor called." << std::endl;
}
void capture() {
std::cout << "Capturing image..." << std::endl;
}
void setImageQuality(int quality) {
std::cout << "Setting image quality to " << quality << std::endl;
}
};
// 芯片类,包含操作菜单、自动拍摄等功能
class Chip {
public:
Chip() {
std::cout << "Chip constructor called." << std::endl;
}
~Chip() {
std::cout << "Chip destructor called." << std::endl;
}
void operateMenu() {
std::cout << "Operating menu..." << std::endl;
}
void autoCapture() {
std::cout << "Auto capturing image..." << std::endl;
}
};
// 继承方式的行车记录仪类
class DashCamInherit : public Camera {
public:
DashCamInherit() : Camera() {
std::cout << "DashCamInherit constructor called." << std::endl;
}
~DashCamInherit() {
std::cout << "DashCamInherit destructor called." << std::endl;
}
};
// 组合方式的行车记录仪类
class DashCamCompose {
private:
Camera camera;
Chip chip;
public:
DashCamCompose() : camera(), chip() {
std::cout << "DashCamCompose constructor called." << std::endl;
}
~DashCamCompose() {
std::cout << "DashCamCompose destructor called." << std::endl;
}
void useCamera() {
camera.capture();
camera.setImageQuality(100);
}
void useChip() {
chip.operateMenu();
chip.autoCapture();
}
};
// 测试代码
int main() {
// 继承方式的测试
std::cout << "Testing inheritance:" << std::endl;
{
DashCamInherit dashCamInherit;
} // DashCamInherit析构函数调用
// 组合方式的测试
std::cout << "Testing composition:" << std::endl;
DashCamCompose dashCamCompose;
dashCamCompose.useCamera();
dashCamCompose.useChip();
return 0;
}
2.2
#include <iostream>
#include <string>
class Camera {
public:
Camera() {
// 构造函数,可以初始化一些摄像机属性
}
// 拍摄方法
void shoot() {
std::cout << "Capturing image with camera..." << std::endl;
}
// 图像质量设定方法
void setImageQuality(int quality) {
// 实现设定图像质量的逻辑
std::cout << "Setting image quality to " << quality << std::endl;
}
// 编码算法方法(示例)
void encodeImage() {
std::cout << "Encoding captured image..." << std::endl;
}
};
class DashboardCameraChip { // 额外的芯片功能类
public:
void operateMenu() {
std::cout << "Operating dashboard camera menu..." << std::endl;
}
void autoShoot() {
std::cout << "Dashboard camera is auto shooting..." << std::endl;
}
};
class DashboardCamera : public Camera { // 继承自Camera类
private:
DashboardCameraChip chip; // 组合DashboardCameraChip类
public:
DashboardCamera() : Camera() {} // 构造函数,初始化Camera和chip
void shoot() override {
chip.autoShoot(); // 调用芯片的自动拍摄功能
Camera::shoot(); // 调用父类的拍摄功能
}
// 使用芯片的操作菜单功能
void operate() {
chip.operateMenu();
}
};
int main() {
DashboardCamera dc;
// 调用DashboardCamera的shoot方法,体验同名函数覆盖
dc.shoot(); // 这里会先调用chip的autoShoot,再调用Camera的shoot
// 调用DashboardCamera的其他方法
dc.setImageQuality(100); // 设置图像质量
dc.operate(); // 使用芯片的操作菜单功能
// 如果需要访问Camera类的未覆盖方法,可以直接调用
dc.encodeImage(); // 编码图像
return 0;
}
2.3
#include <iostream>
#include <vector>
#include <memory>
// 摄像机芯片(组合部分)
class CameraChip {
public:
void operateMenu() {
std::cout << "Operating camera menu..." << std::endl;
}
void autoCapture() {
std::cout << "Capturing automatically..." << std::endl;
}
};
// 摄像机类
class Camera {
protected:
bool isRecording; // 假设摄像机也有录制功能(为了演示多态)
// 摄像、图像质量设定、编码算法等属性...
public:
Camera() : isRecording(false) {}
virtual ~Camera() {}
virtual void record() {
isRecording = true;
std::cout << "Camera is recording..." << std::endl;
}
};
// 行车记录仪类(继承自摄像机,并组合了摄像机芯片)
class DashCam : public Camera {
private:
std::unique_ptr<CameraChip> chip; // 摄像机芯片
public:
DashCam() : Camera(), chip(std::make_unique<CameraChip>()) {}
// 调用摄像机芯片的功能
void operateChipMenu() {
chip->operateMenu();
}
void autoCaptureWithChip() {
chip->autoCapture();
}
void record() override {
Camera::record(); // 调用基类的record方法
// 特定于行车记录仪的录制功能...
std::cout << "DashCam is recording with additional features..." << std::endl;
}
};
// 产品类层次结构的基类指针容器
int main() {
std::vector<std::unique_ptr<Camera>> cameras;
cameras.push_back(std::make_unique<Camera>());
cameras.push_back(std::make_unique<DashCam>());
// 通过基类指针调用虚函数,体验多态
for (const auto& cam : cameras) {
cam->record(); // 无论是摄像机还是行车记录仪,都会调用相应的record方法
}
// 如果需要调用特定于行车记录仪的功能,需要动态转换类型或确保是指向DashCam的指针
if (auto dashCam = dynamic_cast<DashCam*>(cameras[1].get())) {
dashCam->operateChipMenu();
dashCam->autoCaptureWithChip();
}
return 0;
}
- 体会与总结
(一)相关知识点理解
1.继承:在面向对象编程中,继承是一种代码重用机制,允许我们创建一个新的类(子类或派生类),该类继承了一个或多个已存在的类(父类或基类)的特征(包括数据成员和成员函数)。子类可以访问基类的公有和保护成员,但不能直接访问私有成员。
2.组合:组合是一种“有一个”的关系,表示一个类的对象包含另一个类的对象。这允许我们将大型系统分解成更小的、更易于管理的部分。
3.访问权限:C++ 提供了三种访问权限:公有(public)、保护(protected)和私有(private)。公有成员可以在任何地方被访问;保护成员只能在类内部及其派生类中被访问;私有成员只能在类内部被访问。
4.构造函数和析构函数:构造函数用于初始化对象的状态,而析构函数用于在对象生命周期结束时执行清理操作。
5.函数覆盖(或重写):在继承中,如果派生类具有与基类同名的成员函数,并且它们的参数列表也相同,则派生类的函数会覆盖基类的函数。
6.多态:多态是面向对象编程的一个重要特性,它允许使用父类类型的指针或引用来引用子类对象。当通过基类指针或引用调用虚函数时,将调用与指针或引用所指向的对象类型相对应的函数版本。
(二)运行情况分析
1.继承方式下的设计
(1)和(2)(3)类似,我们可以通过创建一个基类(摄像机类)和一个或多个派生类(行车记录仪类)来实现。在行车记录仪类中,我们可以选择性地重写或访问基类的公有和保护成员。
2.组合方式下的设计
(1)在组合方式下,行车记录仪类将包含一个摄像机类的实例作为其成员。这意味着我们需要为这两个类分别编写构造函数和析构函数,并确保在创建和销毁行车记录仪对象时正确地初始化和清理摄像机对象。
(2)当在行车记录仪类中定义与摄像机类同名的函数时,我们可以使用using声明来指定我们想要使用的是哪个版本的函数。
(3)为了创建多态的产品类层次结构,我们需要定义一个基类(可能是Product类),并让摄像机类和行车记录仪类都继承自它。基类应该包含一个或多个虚函数(如operate()),然后在派生类中实现这些函数的具体版本。然后我们可以创建一个基类指针的容器,并将摄像机对象和行车记录仪对象的指针添加到该容器中。通过基类指针调用虚函数时,将调用与指针所指向的对象类型相对应的函数版本。
(三)调试程序获得的经验与体会
通过编写和调试这些代码,我更加深入地理解了面向对象编程的基本概念和技术。我发现了继承和组合之间的区别和联系,并学会了如何有效地使用它们来构建复杂的软件系统。此外,我还学会了如何处理多态、函数覆盖和访问权限等关键问题。在调试过程中,我遇到了许多挑战,但通过仔细分析代码和查阅文档,我最终解决了这些问题。这些经验将有助于我在未来的项目中更加熟练地应用面向对象编程技术。