<返回更多

C++的逐层抽象:从结构体到类、模板

2021-10-18    小智雅汇
加入收藏

C++在C的面向过程概念的基础上提供了面向对象和模板(泛型编程)的语法功能。

下面以一个简单实例(动态数组的简单封装,包括下标的值可以是任意正数值,并提供边界检查)来说明C++是如何实现其逐层抽象的。

1 用结构体实现

// array.h
// array库的接口
#ifndef _array_h
#define _array_h

// 可指定下标范围的数组的存储
struct DoubleArray{
    int low;  
    int high;
    double *storage;
};

// 根据low和high为数组分配空间。分配成功,返回值为true,否则返回值为false
bool initialize(DoubleArray &arr, int low, int high);

// 设置数组元素的值
// 返回值为true表示操作正常,返回值为false表示下标越界
bool insert(const DoubleArray &arr, int index, double value);

// 取数组元素的值
// 返回值为true表示操作正常,返回值为false表示下标越界
bool fatch(const DoubleArray &arr, int index, double &value);

// 回收数组空间
void cleanup(const DoubleArray &arr);

#endif
// array.cpp
// array库的实现
#include "array.h"
#include <IOStream>
using namespace std;

// 根据low和high为数组分配空间。分配成功,返回值为true,否则返回值为false
bool initialize(DoubleArray &arr, int low, int high)
{
    arr.low = low; 
    arr.high = high;
    arr.storage = new double [high - low + 1];
    if (arr.storage == NULL) 
        return false; 
    else 
        return true;
}

// 设置数组元素的值
// 返回值为true表示操作正常,返回值为false表示下标越界
bool insert(const DoubleArray &arr, int index, double value)
{
    if (index < arr.low || index > arr.high) 
        return false;
    arr.storage[index - arr.low] = value;
    return true;
}

// 取数组元素的值
// 返回值为true表示操作正常,返回值为false表示下标越界
bool fatch(const DoubleArray &arr, int index, double &value)
{
    if (index < arr.low || index > arr.high) 
        return false;
    value = arr.storage[index - arr.low] ;
    return true;
}

// 回收数组空间
void cleanup(const DoubleArray &arr)
{  
    if (arr.storage)  
        delete [] arr.storage; 
}

// arrayApp.cpp
// array库的应用示例
#include <iostream>
using namespace std;
#include "array.h"

int main() 
{
	DoubleArray array; 					// DoubleArray是array库中定义的结构体类型
    double value;
	int low, high, i;
	
    //输入数组的下标范围
	cout <<"请输入数组的下标范围:";
	cin >> low >> high;
	
	//初始化数组array,下标范围为20到30
	if (!initialize(array, low, high)) { 
        cout <<"空间分配失败" ; return 1;
    }
	
    for (i = low; i <= high; ++i) { 		// 数组元素的输入
		cout <<"请输入第"<< i <<"个元素:";
		cin >> value;
		insert(array, i, value); 		     // 将value存入数组array的第i个元素
    }
	
    while (true) { 					         // 读取第i个元素
		cout <<"请输入要读取的元素序号(0表示结束):";
		cin >> i;
		if (i == 0) 
            break;
		if (fatch(array, i, value)) 
            cout << value << endl;
		else 
            cout <<"下标越界n";
    }
	
    cleanup(array);					        //回收存储数组元素的空间
	
    return 0;
}

相关的函数全部有一个结构体函数参数,来操作结构体。通过头文件包括结构体和函数声明来实现模块化并提供接口,实现一个较松散的数据与函数的结合。

而类则不同,类除了提供数据聚合的结构体功能以外,还可以将函数封装进去,通过类名实现名字空间,并为成员函数提供一个隐含的指向类对象的this指针,使其成员函数能够访问并操作数据成员。

2 用一个不完整的类来模拟结构体实现

// array.h
// 改进后的array接口
#ifndef _array_h
#define _array_h

struct DoubleArray{
    int low;  
    int high;
    double *storage;
    
    // 根据low和high为数组分配空间。分配成功,返回值为true,否则返回值为false
    bool initialize(int lh, int rh);
    
    // 设置数组元素的值
    // 返回值为true表示操作正常,返回值为false表示下标越界
    bool insert(int index, double value);
    
    // 取数组元素的值
    // 返回值为true表示操作正常,返回值为false表示下标越界
    bool fatch(int index, double &value);
    
    // 回收数组空间
    void cleanup();
};

#endif
// array.cpp
// 改进后的array库的实现
#include "array.h"
#include <iostream>
using namespace std;

// 根据low和high为数组分配空间。分配成功,返回值为true,否则返回值为false
bool DoubleArray::initialize(int lh, int rh)
{
    low = lh;
    high = rh;
    storage = new double [high - low + 1];
    if (storage == NULL) 
        return false; 
    else return true;
}

// 设置数组元素的值
// 返回值为true表示操作正常,返回值为false表示下标越界
bool DoubleArray::insert(int index, double value)
{   
    if (index < low || index > high) 
        return false;
    storage[index - low] = value;
    return true;
}

// 取数组元素的值
// 返回值为true表示操作正常,返回值为false表示下标越界
bool DoubleArray::fatch(int index, double &value)
{
    if (index < low || index > high) 
        return false;
    value = storage[index - low] ;
    return true;
}

//回收数组空间
void DoubleArray::cleanup()
{   
    if (storage) 
        delete [] storage; 
}

// arrayapp.cpp
// 改进后的array库的应用示例
#include <iostream>
using namespace std;
#include "array.h"

int main()
{
    DoubleArray array;
    double value;
    int low, high, i;
    
    //输入数组的下标范围
    cout <<"请输入数组的下标范围:";
    cin >> low >> high;
    
    if (!array.initialize(low, high)) {         // 为array申请存储数组元素的空间
        cout <<"空间分配失败" ; return 1;
    }
    
    //数组array的初始化
    for (i = low; i <= high; ++i) {             //数组元素的输入
        cout <<"请输入第"<< i <<"个元素:";
        cin >> value;
        array.insert(i, value);
    }
    
    while (true) {                              //数组元素的访问
        cout <<"请输入要访问的元素序号(0表示结束):";
        cin >> i;
        if (i == 0) 
            break;
        if (array.fatch(i, value)) 
            cout << value << endl;
        else 
            cout <<"下标越界n";
    }
    
    array.cleanup();                //归还存储数组元素的空间
    
    return 0;
}

3 用定义较为完整的类来实现

类还实现了资源获取即初始化(RAII, Resource Acquisition Is Initialization)以及自动实现资源析构的功能,以及对运算符的重载等功能。

// DoubleArray.h
// DoubleArray类的定义
#ifndef _array_h
#define _array_h

#include <iostream.h>

class DoubleArray{
    friend ostream &operator<<(ostream &os, const DoubleArray &obj);
    friend istream &operator>>(istream &is, DoubleArray &obj);
    friend bool operator==(const DoubleArray &obj1, const DoubleArray &obj2);
    
private:
    int low;  
    int high;
    double *storage;
    
public:
    // 构造函数根据low和high为数组分配空间
    DoubleArray(int lh = 0, int rh = 0):low(lh), high(rh)
    {
        storage = new double [high - low + 1]; 
    }	
    
    // 复制构造函数
    DoubleArray(const DoubleArray &arr);   
    
    // 赋值运算符重载函数
    DoubleArray &operator=(const DoubleArray &right);
    
    // 下标运算符重载函数
    double & operator[](int index);              // 作为左值
    const double & operator[](int index) const;  // 作为右值
    
    // 取数组的一部分形成一个新的数组
    DoubleArray operator()(int start, int end, int lh);
    
    // 析构函数
    ~DoubleArray() { 
        if (storage) 
            delete [] storage; 
    }
};
#endif

// DoubleArray.cpp
// DoubleArray类的实现
#include <cassert>
#include "DoubleArray.h"

DoubleArray::DoubleArray(const DoubleArray &arr)
{
    low = arr.low; 
    high = arr.high;
    storage = new double [high - low + 1];
    for (int i = 0; i < high -low + 1; ++i)  
        storage[i] = arr.storage[i];
}

DoubleArray &DoubleArray::operator=(const DoubleArray & a)
{
    if (this == &a)                         // 防止自己复制自己
        return *this;
    delete [] storage;                      // 归还空间
    
    low = a.low;  high = a.high;
    storage = new double[high - low + 1];   // 根据新的数组大小重新申请空间
    for (int i=0; i <= high - low; ++i) 
        storage[i] = a.storage[i];          // 复制数组元素
    
    return *this;
}

double & DoubleArray::operator[](int index)
{ 
    assert(index >= low && index <= high); 
    return storage[index - low];
}

const double & DoubleArray::operator[](int index) const
{
    assert(index >= low && index <= high); 
    return storage[index - low];
}

ostream &operator<<(ostream &os, const DoubleArray &obj)
{
    os <<"数组内容为:n";
    for (int i=obj.low; i<=obj.high; ++i) 
        os << obj[i] << 't';
    os << endl;
    
    return os;
}

istream &operator>>(istream &is, DoubleArray &obj)
{
    cout <<"请输入数组元素["<< obj.low <<", "<< obj.high <<"]:n";
    for (int i=obj.low; i<=obj.high ; ++i)   
        is >> obj[i] ;
    
    return is;
}

bool operator==(const DoubleArray &obj1, const DoubleArray &obj2)
{
    if (obj1.low != obj2.low || obj1.high != obj2.high) 
        return false;
    for (int i = obj1.low; i<=obj1.high; ++i) 
        if (obj1[i] != obj2[i]) 
            return false;
    return true;
}

DoubleArray DoubleArray::operator()(int start, int end, int lh)
{
    assert (start <= end && start >= low && end <= high );  // 判断范围是否正确
    
    DoubleArray tmp(lh, lh + end - start);                  // 为取出的数组准备空间
    for (int i = 0; i < end - start + 1; ++i) 
        tmp.storage[i] = storage[start + i - low];
    
    return tmp;
}
// DoubleArrayApp.cpp
// DoubleArray类的使用
#include "DoubleArray.h"

int main()
{
    DoubleArray array1(20,30), array2;
    
    cin >> array1;                      // 利用流提取运算符重载输入array1
    cout <<"array1 "; cout << array1;   // 利用流插入运算符重载输出array1
    
    array2 = array1;                    // 利用赋值运算符重载将array1赋给array2
    
    cout <<"执行 array2 = array1, array2 ";
    cout << array2;
    
    // 利用==重载比较array1和array2
    cout <<"array1 == array2 是 "<< ((array1 == array2)  ? "true" : "false") << endl; 
    
    array2[25] = 0;                      // 利用下标运算符重载为array2的元素赋值
    
    cout <<"执行array[25] = 0后, array1 == array2 是 "
        << ((array1 == array2)  ? "true" : "false") << endl; 
    
    array2 = array1(22, 25, 2);
    cout <<"执行array2 = array1(22, 25, 2)后, array2 的值为: "<< array2;	
    
    while(1);
    return 0;
}

4 用模板实现泛型

强类型一定程度上实现了类型在编译期的检查功能,而模板却可以让类并不囿于过于具体的类型:

// array.h
#include <iostream.h>
// 类模板的友元:重载输入运算符
template<class T> 
    class Array;	                                      // 类模板Array的声明
template<class T> 
    ostream &operator<<(ostream &os, const Array<T>&obj); // 输出重载声明

template <class T>
class Array {
    friend ostream &operator<<(ostream &os, const Array<T>&obj);
    
private:
    int low;  
    int high;
    T *storage;
    
public:
    // 根据low和high为数组分配空间。分配成功,返回值为true,否则返回值为false
    Array(int lh = 0, int rh = 0):low(lh),high(rh)
    { 
        storage = new T [high - low + 1]; 
    }
    
    // 复制构造函数
    Array(const Array &arr);
    
    // 赋值运算符重载函数
    Array &operator=(const Array & a);
    
    // 下标运算符重载函数
    T & operator[](int index);
    const T & operator[](int index) const;  // 作为右值
    
    // 回收数组空间
    ~Array(){
        if(storage)
            delete [] storage; 
    }  
};

template <class T>
T & Array<T>::operator[](int index)
{
    if (index < low || index > high)
    {
        cout <<"下标越界"; 
        return;
    }
    return storage[index - low];
}

template <class T>
const T & Array<T>::operator[](int index) const
{
    if (index < low || index > high)
    {
        cout <<"下标越界"; 
        return;
    }
    return storage[index - low];
}

// 类模板的友元:重载输出运算符
template<class T>
ostream &operator<<(ostream &os, const Array<T>&obj)
{
    os << endl;
    for (int i=0; i < obj.high - obj.low + 1; ++i) 
        os << obj.storage[i] << 't';
    return os;
}

template<class T>
Array<T>::Array(const Array<T> &arr)
{
    low = arr.low; 
    high = arr.high;
    storage = new T [high - low + 1];
    for (int i = 0; i < high -low + 1; ++i)  
        storage[i] = arr.storage[i];
}

template<class T>
Array<T> &Array<T>::operator=(const Array<T> & a)
{
    if (this == &a)                         // 防止自己复制自己
        return *this;
    
    delete [] storage;                      // 归还空间
    
    low = a.low;  high = a.high;
    storage = new T[high - low + 1];        // 根据新的数组大小重新申请空间
    for (int i=0; i <= high - low; ++i) 
        storage[i] = a.storage[i];          // 复制数组元素
    
    return *this;
}

// main.cpp

#include <iostream.h>
#include "array.h"

int main()
{
    int start, end;
    cout<<"请输入数组的下标和上标,如1 9:";
    cin>>start>>end;
    Array<double> arr(start,end), arr2;
    for(int i = start ; i<= end-start+1 ; i++)
        arr[i] = i*0.9;
    arr[8] = 8.8;
    arr2 = arr;
    cout<<arr2<<endl;

    while(1);
    return 0;
}

-End-

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>