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-