- 实验题目
对如下多项式(Polynomial)编写类定义
其中,n为多项式的次数。完成如下功能:
- 可存储任意大的多项式(提示:可用动态数组实现)。
- 定义构造函数、析构函数、拷贝构造函数。
- 包含一个static成员存储定义的多项式数量。
- 定义一个成员函数输出多项式。(可参照-x^4-6x^3+5格式输出,注意化简)
- 定义一个成员函数计算多项式的值。
- 重载“+”运算符,实现两个多项式相加。
- 重载“-”运算符,实现两个多项式相减。
- 重载“*”运算符,实现两个多项式相乘。
- 重载“=”运算符,实现两个多项式的赋值运算。
- 在main函数中编写测试代码。
要求:采用多文件实现。考虑:哪些成员函数可以声明为const,
把其中某个运算符重载为友元函数。
- 解决方案
1.类定义:定义Polynomial类,包含动态数组来存储多项式的项 (系数和指数)。
2.静态成员:定义一个静态成员变量count来跟踪多项式对象的数量。
3.成员函数:
Print:遍历项并输出多项式,注意处理负系数和省略零项。
Evaluate:使用Horner法则或循环遍历项来计算多项式的值。
4.运算符重载:实现加法、减法、乘法和赋值运算符。
5.友元函数:将减法运算符重载为友元函数,因为它需要访问类的私有成员。
6.测试:在main函数中创建多项式对象,测试所有功能。
- 程序清单
Polynomial.h
#ifndef POLYNOMIAL_H
#define POLYNOMIAL_H
#include <iostream>
#include <vector>
class Polynomial {
private:
std::vector<int> coeffs; // 系数数组,从最高次到0次
static int count; // 静态成员变量,记录定义的多项式数量
public:
// 构造函数
Polynomial();
Polynomial(const std::initializer_list<int>& initList);
// 析构函数
~Polynomial();
// 拷贝构造函数
Polynomial(const Polynomial& other);
// 赋值运算符
Polynomial& operator=(const Polynomial& other);
// 输出多项式
void print() const;
// 计算多项式的值
int evaluate(int x) const;
// "+" 运算符重载
Polynomial operator+(const Polynomial& other) const;
// "-" 运算符重载
Polynomial operator-(const Polynomial& other) const;
// "*" 运算符重载(友元函数)
friend Polynomial operator*(const Polynomial& lhs, const Polynomial& rhs);
// 静态成员变量访问器
static int getCount() { return count; }
};
#endif // POLYNOMIAL_H
Polynomial.cpp
#include "Polynomial.h"
#include <iostream>
#include <algorithm>
// 初始化静态成员变量
int Polynomial::count = 0;
// 构造函数
Polynomial::Polynomial() : coeffs() {
++count;
}
Polynomial::Polynomial(const std::initializer_list<int>& initList) : coeffs(initList) {
++count;
// 这里可以添加代码以去除末尾的零
}
// 析构函数
Polynomial::~Polynomial() {
--count;
}
// 拷贝构造函数
Polynomial::Polynomial(const Polynomial& other) : coeffs(other.coeffs) {
++count;
}
// 赋值运算符
Polynomial& Polynomial::operator=(const Polynomial& other) {
if (this != &other) {
coeffs = other.coeffs;
}
return *this;
}
// 输出多项式
void Polynomial::print() const {
bool isFirstTerm = true;
bool isPositive = true;
for (int i = coeffs.size() -1; i >= 0; --i) {
if (coeffs[i] != 0) {
if (!isFirstTerm) {
std::cout << (isPositive ? " + " : " - ");
}
isFirstTerm = false;
isPositive = coeffs[i] > 0;
if (i != coeffs.size()) {
std::cout << std::abs(coeffs[i]) << "x^" << i;
}
else {
std::cout << coeffs[i];
if(i==0)
isFirstTerm = true;
}
}
}
std::cout << std::endl;
}
// 计算多项式的值
int Polynomial::evaluate(int x) const {
int result = 0;
for (size_t i = 0; i < coeffs.size(); ++i) {
result += coeffs[i] * std::pow(x, i);
}
return result;
}
// "+" 运算符重载
Polynomial Polynomial::operator+(const Polynomial& other) const {
Polynomial result;
int maxN = std::max(coeffs.size(), other.coeffs.size()) - 1;
result.coeffs.resize(maxN + 1, 0);
for (int i = 0; i <= maxN; ++i) {
result.coeffs[i] = (i < coeffs.size() ? coeffs[i] : 0) +
(i < other.coeffs.size() ? other.coeffs[i] : 0);
}
return result;
}
// "-" 运算符重载
Polynomial Polynomial::operator-(const Polynomial& other) const {
Polynomial result;
int maxN = std::max(coeffs.size(), other.coeffs.size()) - 1;
result.coeffs.resize(maxN + 1, 0);
for (int i = 0; i <= maxN; ++i) {
result.coeffs[i] = (i < coeffs.size() ? coeffs[i] : 0) -
(i < other.coeffs.size() ? other.coeffs[i] : 0);
}
return result;
}
// "*" 运算符重载(友元函数)
Polynomial operator*(const Polynomial& lhs, const Polynomial& rhs) {
Polynomial result;
int maxN = lhs.coeffs.size() + rhs.coeffs.size() - 2;
result.coeffs.resize(maxN + 1, 0);
for (size_t i = 0; i < lhs.coeffs.size(); ++i) {
for (size_t j = 0; j < rhs.coeffs.size(); ++j) {
result.coeffs[i + j] += lhs.coeffs[i] * rhs.coeffs[j];
}
}
return result;
}
main.cpp
#include "Polynomial.h"
#include <iostream>
int main() {
// 测试代码...
Polynomial p1{ 1, 2, 3,4,5,6 }; // 3x^2 + 2x + 1
Polynomial p2{ 4, 5, 6 }; // 6x^2 + 5x + 4
p1.print();
p2.print();
std::cout << "Sum: ";
(p1 + p2).print();
std::cout << "Difference: ";
(p1 - p2).print();
std::cout << "Product: ";
(p1 * p2).print();
std::cout << "Polynomial count: " << Polynomial::getCount() << std::endl;
return 0;
}
- 程序运行结果
- 体会与总结
(一)知识点理解
我深入理解了C++面向对象编程的概念,包括类定义、构造函数、析构函数、拷贝构造函数、静态成员、运算符重载和友元函数。
1.类定义(Class Definition):
类是面向对象编程的核心。它定义了一个对象的模板或蓝图,描述了对象应有的属性和方法。类定义通常包括数据成员(属性)和成员函数(方法)。
2.构造函数(Constructor):
构造函数是一个特殊的成员函数,用于初始化类的对象。当创建类的对象时,构造函数会被自动调用。构造函数没有返回类型(连void也没有),并且其名称与类名相同。
3.析构函数(Destructor):
析构函数是另一个特殊的成员函数,当类的对象离开其作用域或被显式删除时,析构函数会被自动调用。析构函数用于释放对象可能占用的资源,如动态分配的内存。析构函数的名称是类名前加上波浪线(~),也没有返回类型。
4.拷贝构造函数(Copy Constructor):
拷贝构造函数是一个特殊的构造函数,用于从一个已存在的对象创建一个新的对象,并将其初始化为与已存在对象相同的状态。拷贝构造函数只有一个参数,该参数是对同类对象的引用(通常为const引用),用于从源对象复制数据。
5.静态成员(Static Member):
静态成员属于类本身,而不是类的某个对象。这意味着无论创建多少个类的对象,静态成员都只有一个副本。静态成员可以是数据成员(静态变量)或成员函数(静态方法)。静态成员变量在类外部定义,而静态成员函数可以直接访问类的静态成员和其他非静态成员。
6.运算符重载(Operator Overloading):
运算符重载允许程序员重新定义或重载大部分内置运算符,以便它们可以用于用户自定义的数据类型。例如,可以重载+运算符使其能够用于两个自定义类对象的加法操作。
7.友元函数(Friend Function):
友元函数不是类的成员函数,但它可以访问类的私有和保护成员。友元函数可以是普通函数,也可以是其他类的成员函数。通过在类定义中声明为友元,该函数就获得了访问类私有成员的权限。注意,过度使用友元可能会破坏封装性,因此应谨慎使用。
(二)运行情况分析
在编写和测试代码时,要注意处理边界情况和异常情况,例如零系数项、负系数和多项式相加/相减/相乘后的化简。
(三)调试程序获得的经验与体会
在调试过程中,可能会遇到各种问题,如内存泄漏、访问越界、逻辑错误等。使用调试工具(如GDB)和打印语句可以帮助你定位问题。通过这个项目,学会了如何设计和实现一个复杂的类,并理解如何组织代码以使其易于维护和扩展。此外,还学会了如何编写代码来处理各种情况。