西安石油大学C++上机实验 上机五:模板和异常处理程序设计(2 学时)

简介: 西安石油大学C++上机实验 上机五:模板和异常处理程序设计(2 学时)

上机五:模板和异常处理程序设计(2 学时)

实验目的

1.了解参数多态性的概念。

2.熟悉函数模板和类模析的设计和使用方法。

3.掌握 C++异常处理方法和异常类的设计。

了解参数多态性的概念。

熟练掌握函数模板和类模析的设计和使用方法。

实验内容

P197:7.9

设计一个考虑异常情况的分数类模板,实现基本分数运算和分数的输出,并编写测试程序进行测试。

测试例题

[例 7.2] 设计一下复数类模板。要求:

(1)复数类模板的成员函数包括加和输出;

(2)成员函数加既可以是两个复数类模板对象相加,也可以是一个复数类模板对象与另一个模板参数作为实部的数值相加;

(3)设计一个测试主函数,要求测试主函数中同时定义实参为 float 的复数类对象和实参为 double 的复数类对象。

// TemplateComplex.h
template <class T>
class Complex{
 T real;
 T imag;
public:
 Complex(T x=0, T y=0);
 Complex Add(const Complex x);
 Complex Add(const T x);
void show() const;
};
template <class T>
Complex<T>::Complex(T x, T y)
{
real = x;
imag = y;
}
template <class T>
Complex<T> Complex<T>::Add(const Complex<T> x)
{
return Complex<T>(real+x.real, imag+x.imag);
}
template <class T>
Complex<T> Complex<T>::Add(const T x)
{
return Complex<T>(real+x, imag);
}
template <class T>
void Complex<T>::show() const
{
cout<<"real is "<<real;
cout<<" imag is "<<imag<<endl;
}
在主文件中 work5.cpp 中编辑测试代码:
#include <iostream.h>
#include "TemplateComplex.h"
int main(int argc, char* argv[])
{
Complex<float> x(1.1, 1.1), y(2.2, 2.2), z;
Complex<double> u(1.111111, 1.111111), v(2.22222, 2.22222), w;
z = x.Add(y);
cout<<"z is: ";
z.show();
w = u.Add(v);
cout<<"w is: ";
w.show();
return 0;
}
[例 7.3] 设计一个求两个数中较大数的函数模板
//Max.h
template <class T>
T max(T x, T y)
{
 return (x>y)? x:y;
}
在主文件中 work5.cpp 中编辑测试代码:
#include <iostream.h>
#include "Max.h"
int main(int argc, char* argv[])
{
int myIntX = 5, myIntY = 8, myIntC;
float myFloatX = 5.6, myFloatY = 8.9, myFloatC;
54
myIntC = max(myIntX, myIntY);
cout<<"myIntC = "<<myIntC<<endl;
myFloatC = max(myFloatX, myFloatY);
cout<<"myFloatC = "<<myFloatC<<endl;
}
//SeqStack.h
class PushOnFull{ //入栈满异常类
 int value;
public:
 PushOnFull(int x) : value(x){}
 int Value(void){ return value; }
};
class PopOnEmpty{};
class SeqStack{
int *data;
int MaxStackSize;
int top;
public:
SeqStack(int n)
{
top = 0;
MaxStackSize = 0;
data = new int[n];
}
~SeqStack(){ delete data; }
void Push(const int item);
int Pop();
};
void SeqStack::Push(const int item)
{
 if(top==MaxStackSize)
 throw PushOnFull(item);
 data[top] = item;
 top++;
}
int SeqStack::Pop()
{
if(top == 0) throw PopOnEmpty();
top--;
return data[top];
}
在主文件中 work5.cpp 中编辑测试代码:
#include <iostream.h>
#include "SeqStack.h"
int main(int argc, char* argv[])
{
SeqStack myStack(10);
try{
for(int i=0; i<11; i++)
myStack.Push(i+1);
}
catch(PushOnFull obj){
cout<<"Stack is full"<<endl;
cout<<"the element is: "<<obj.Value()<<endl;
}
try{
for(int i=0; i<11; i++)
cout<<myStack.Pop()<<" ";
}
catch(PopOnEmpty){
cout<<"Stack is empty"<<endl;
}
}

P197:7.9

设计一个考虑异常情况的分数类模板,实现基本分数运算和分数的输出,并编写测试程序进行测试。

class Fract{
public:
int n; //分子
int m; //分母
 Fract(int a=0, int b=1):n(a), m(b){}
 Fract Add(const Fract x);
Fract Div(const Fract x);
void show() const;
int MaxComm(int a, int b);
};
Fract Fract::Div(const Fract x)
{
57
58
int a = n*x.m;
int b = m*x.n;
if(b == 0)throw 0;
int c = MaxComm(a, b);
return Fract(a/c, b/c);
}
Fract Fract::Add(const Fract x)
{
int a = n*x.m + m*x.n;
int b = m*x.m;
int c = MaxComm(a, b);
return Fract(a/c, b/c);
}
int Fract::MaxComm(int a, int b)//求 a,b 的最大公约数
{
int r=a%b;
while(r!=0)
{
a = b;
b = r;
r = a%b;
}
return(b);
}
void Fract::show() const
{
cout<<n<<"/"<<m<<endl;
}
(3)在主文件中 work5.cpp 中编辑测试代码:
#include <iostream.h>
#include "Fract.h"
int main(int argc, char* argv[])
{
Fract f1(3, 4), f2(7, 16), f3;
try{
59
f1.Div(f3);
}
catch(int){
cout<<"Divided by Zero!"<<endl;
}
f3 = f1.Add(f2);
f3.show();
}

CHATgpt 会怎么来处理?

好的,下面是一个考虑异常情况的分数类模板,并实现了基本分数运算和分数输出的代码:
~~~c++
#include<iostream>
#include<exception>
using namespace std;
//自定义除数为0异常
struct DIVBYZERO: public exception
{
    const char* what() const throw()
    {
        return "Error: Division by zero!\n";
    }
};
template<class T>
class Fraction
{
    private:
        T numerator; // 分子
        T denominator; // 分母
    public:
        // 构造函数
        Fraction(T num, T den);
        // getter 方法
        T getNumerator();
        T getDenominator();
        // setter 方法
        void setNumerator(T num);
        void setDenominator(T den);
        // 重载"+"
        Fraction operator+(Fraction f);
        // 重载"-"
        Fraction operator-(Fraction f);
        // 重载"*"
        Fraction operator*(Fraction f);
        // 重载"/"
        Fraction operator/(Fraction f);
        // 输出分数
        void print();
};
// 构造函数实现
template<class T>
Fraction<T>::Fraction(T num, T den)
{
    if(den == 0) // 如果分母为0则抛出DIVBYZERO异常
        throw DIVBYZERO();
    numerator = num;
    denominator = den;
}
// getter 方法实现
template<class T>
T Fraction<T>::getNumerator()
{
    return numerator;
}
template<class T>
T Fraction<T>::getDenominator()
{
    return denominator;
}
// setter 方法实现
template<class T>
void Fraction<T>::setNumerator(T num)
{
    numerator = num;
}
template<class T>
void Fraction<T>::setDenominator(T den)
{
    // 如果分母为0则抛出DIVBYZERO异常
    if(den == 0)
        throw DIVBYZERO();
    else
        denominator = den;
}
// 重载"+" 实现
template<class T>
Fraction<T> Fraction<T>::operator+(Fraction f)
{
    T num = numerator * f.denominator + f.numerator * denominator;
    T den = denominator * f.denominator;
    return Fraction(num, den);
}
// 重载"-" 实现
template<class T>
Fraction<T> Fraction<T>::operator-(Fraction f)
{
    T num = numerator * f.denominator - f.numerator * denominator;
    T den = denominator * f.denominator;
    return Fraction(num, den);
}
// 重载"*" 实现
template<class T>
Fraction<T> Fraction<T>::operator*(Fraction f)
{
    T num = numerator * f.numerator;
    T den = denominator * f.denominator;
    return Fraction(num, den);
}
// 重载"/" 实现
template<class T>
Fraction<T> Fraction<T>::operator/(Fraction f)
{
    // 如果除数为0则抛出DIVBYZERO异常
    if(f.numerator == 0)
        throw DIVBYZERO();
    T num = numerator * f.denominator;
    T den = denominator * f.numerator;
    return Fraction(num, den);
}
//输出分数
template<class T>
void Fraction<T>::print()
{
    cout << " " << numerator << "/" << denominator << " ";
}
//测试
int main()
{
    try
    {
        Fraction<int> f1(3,8), f2(1,4);
        Fraction<int> f3 = f1 + f2;
        Fraction<int> f4 = f1 - f2;
        Fraction<int> f5 = f1 * f2;
        Fraction<int> f6 = f1 / f2;
        cout << "f1:"; f1.print(); cout << endl;
        cout << "f2:"; f2.print(); cout << endl;
        cout << "f1+f2:"; f3.print(); cout << endl;
        cout << "f1-f2:"; f4.print(); cout << endl;
        cout << "f1*f2:"; f5.print(); cout << endl;
        cout << "f1/f2:"; f6.print(); cout << endl;
        Fraction<double> f7(3.2, 1.5), f8(0, 4);
        Fraction<double> f9 = f7 + f8;
    }
    catch(DIVBYZERO &e)
    {
        cout << e.what() <<endl;
    }
    return 0;
~~~`
代码上注释已经比较详细了,主要实现了以下功能:
1. 自定义除数为 0 异常(DIVBYZERO)。
2. 分别用构造函数和 setter 方法对分子和分母进行初始化,并提供 getter 方法获取成员变量值。
3. 实现基本分数运算符重载( + , - , \* , / )。
4. 实现分数的输出功能。
在测试程序中,我们创建了两个不同数据类型的分数类(int 型和 double 型),并对其+、-、\*、/四种运算符进行了使用。同时,也考虑到了除数为 0 时抛出错误处理。
目录
相关文章
|
3月前
|
存储 算法 安全
c++模板进阶操作——非类型模板参数、模板的特化以及模板的分离编译
在 C++ 中,仿函数(Functor)是指重载了函数调用运算符()的对象。仿函数可以像普通函数一样被调用,但它们实际上是对象,可以携带状态并具有更多功能。与普通函数相比,仿函数具有更强的灵活性和可扩展性。仿函数通常通过定义一个包含operator()的类来实现。public:// 重载函数调用运算符Add add;// 创建 Add 类的对象// 使用仿函数return 0;
121 0
|
3月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
89 0
|
6月前
|
C语言 C++ 开发者
【c++】异常处理
本文深入探讨了C++中的异常处理机制,从基础概念到实际应用进行全面解析。首先介绍了异常的作用及优势,相比C语言的错误码方式,C++通过抛出对象实现更全面的错误处理。接着分析了异常的使用方法,包括`try-catch`结构、异常传播与捕获规则,以及栈展开的过程。文章还讨论了异常安全问题,如内存泄漏和资源清理,并引出智能指针的解决方案。此外,介绍了C++11的`noexcept`规范和标准库异常体系,帮助开发者构建更健壮的应用程序。最后总结了异常的优点与潜在问题,为后续学习智能指针埋下伏笔。
151 15
|
6月前
|
编译器 C++
模板(C++)
本内容主要讲解了C++中的函数模板与类模板。函数模板是一个与类型无关的函数家族,使用时根据实参类型生成特定版本,其定义可用`typename`或`class`作为关键字。函数模板实例化分为隐式和显式,前者由编译器推导类型,后者手动指定类型。同时,非模板函数优先于同名模板函数调用,且模板函数不支持自动类型转换。类模板则通过在类名后加`&lt;&gt;`指定类型实例化,生成具体类。最后,语录鼓励大家继续努力,技术不断进步!
|
7月前
|
编译器 C++
㉿㉿㉿c++模板的初阶(通俗易懂简化版)㉿㉿㉿
㉿㉿㉿c++模板的初阶(通俗易懂简化版)㉿㉿㉿
|
7月前
|
安全 C++
【c++】模板详解(2)
本文深入探讨了C++模板的高级特性,包括非类型模板参数、模板特化和模板分离编译。通过具体代码示例,详细讲解了非类型参数的应用场景及其限制,函数模板和类模板的特化方式,以及分离编译时可能出现的链接错误及解决方案。最后总结了模板的优点如提高代码复用性和类型安全,以及缺点如增加编译时间和代码复杂度。通过本文的学习,读者可以进一步加深对C++模板的理解并灵活应用于实际编程中。
97 0
|
7月前
|
存储 安全 算法
深入理解C++模板编程:从基础到进阶
在C++编程中,模板是实现泛型编程的关键工具。模板使得代码能够适用于不同的数据类型,极大地提升了代码复用性、灵活性和可维护性。本文将深入探讨模板编程的基础知识,包括函数模板和类模板的定义、使用、以及它们的实例化和匹配规则。
|
10月前
|
安全 编译器 C++
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
329 4
|
7月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
3月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
167 0