第十九天(C++代码重用IV)

        昨晚写完已断网,故而今早上传。另,可能是这章内容太多,可能是我太过啰嗦,这章居然被我分了五部分。今天或者明天,还会有part V


2012-3-22(Reusing Code in C++part IV)

13. Class Templates

Inheritance and containment aren't always the solution when you want to reuse code. Instead, using class templates are more commonly. Like function templates, templates instructions to the C++ compiler about how to generate class definitions. Unlike function templates, class templates provide parameterized types---that is, the capable of passing type name as an argument to a recipe for building a class.

I. Syntax

A typical class model would like this:         

class exam
{
private:
  	int member;
public:
   	int function1();
	exam function2();
};
Then, if we want to declare a class template,modify it as follows:
template <class Type>		//or <typename Type>
class exam
{
private:
  	Type member;
public:
   	Type function1();
	exam function2();
}

Also,you need to make a little change when defining member functions:

template <class Type>
Type exam<Type>::function1()  {/*function body*/}

template <class Type>
exam<Type> exam<Type>::function2() {/*function body*/}
We need to change the class qualifier from exam:: to exam<Type>:: . But we can use exam:: or exam instead of exam<Type>:: or exam<Type> inside the template declaration and template function definitions.

II. Caution

Again, class templates are not class and member function definitions. Rather, they tell the compiler to how to generate a specific class. A particular actualization of a template is called an instantiation or a specialization.Because, the templates aren't functions, placing the template member functions in a separate implementation file won't work, unless you use a compiler that has implemented the new export keyword.

But most of compilers,including Microsoft Visual Studio 2010 Express that I am using are not yet support this keyword  (warning in VS2010):

        'export' keyword is not yet supported,but reserved for future use

Looking for the reason in the Internet: too complex to implement.

It's strange that when I try to separate declaration and implementation, my compiler reports no problem.I don't know why. For compatibility, we are supposed to place all the template information in a herder file.

 

14. Design a Simple Array Template

Templates are frequently used for container classes because the idea of type parameters matches well with the need to apply a common storage plan to a variety of types. A typical array template has the following functions (a portion):

  •   size ();                 //return the number of elements
  •   operator []();        //set and get the value of element

We need to specify an array size when creating an array. Two techniques to reach this goal: one is use a dynamic array within the class and a constructor argument to provide the number of elements. Another approach is to use a template argument to provide the size for a regular an ordinary array.

I. Dynamic Array 

#ifndef _DARRAY_
#define _DARRAY_

template <typename T>
class DArray
{
private:
    int array_size;
    T* elems;
public:
    DArray (int size = 10);      //contructor
    DArray (const DArray& da);  //copy contructor
    ~DArray(){delete[] elems;}    //destructor

    int size() {return array_size;}
    const T& operator [](int i) const;   //prepare for const objects
    T& operator [](int i);          	      //get & set certain element
    DArray& operator =(const DArray& da);    //assignment operator
};

template <typename T>
DArray<T>::DArray(int size = 10): array_size(size)
{
    elems = new T[size];
}

template <typename T>
DArray<T>::DArray(const DArray& da)
{
    array_size = da.array_size;
    elems = new T[array_size];

    for(int i = 0; i< array_size; i++) elems[i] = da.elems[i];
}

template <typename T>
const T& DArray<T>::operator [](int i) const
{
    return elems[i];
}

template <typename T>
T& DArray<T>::operator [](int i)
{
    return elems[i];
}

template <typename T>
DArray<T>& DArray<T>::operator =(const DArray& da)
{
    if(this == &da) return *this;

    delete[] elems;
    array_size = da.array_size;
    elems = new T[array_size];
    for(int i = 0; i< array_size; i++)
        elems[i] = da.elems[i];
    return *this;
}
#endif
Using dynamic array internally, so the class needs a destructor, copy constructor and an assignment operator.

II. Non-Type Arguments

#ifndef _NARRAY_
#define _NARRAY_

template <typename T, int n>
class NArray
{
private:
    T elems[n];
public:
NArray() {}         //default constructor
//create an object that all elements are e
explicit NArray(const T& e); 

int size() const { return n; };
const T& operator [](int i) const;
T& operator [](int i);
};

template <typename T, int n>
NArray<T,n>::NArray(const T& e)
{
    for(int i = 0; i< n; i++) elems[i] = e;
}

template <typename T, int n>
const T& NArray<T,n>::operator[](int i)const
{
    return elems[i];
}

template <typename T, int n>
T& NArray<T,n>::operator[](int i)
{
    return elems[i];
}
#endif
template heading template < typename T, int n> , whose second kind of parameter specifies a particular type instead of acing as a generic for a type, is called a non-type (or expression ) argument .

Non-type arguments have some restrictions. Anon-type can be an integral type, an enumeration type, a reference or a pointer. Also, the templates code can't modify the value of the argument or take its address. In other word, expression like n++ or &n  would not be allowed inside the class templates. And when instantiate a template, the value used for the expression argument should be a constant expression.

III. Testing

Two techniques have the same name of interface, so I can use a similar test program.

#include <iostream>
//#include "NArray.h"
#include "DArray.h"

using namespace std;

int main()
{
   //NArray<double,7> da(5.0);
   DArray<double> da(7);
   cout << da.size() << endl;

   for(int i = 0; i< 6; i++) da[i] = double(i * 2);
   //const NArray<double,7> nda = da;
   const DArray<double> nda = da;
   
   for(int i = 0; i< nda.size(); i++) 
      cout << nda[i] << " ";
   cout << endl;   
   for(int i = 0; i< da.size(); i++) 
       cout << da[i] << " ";
}

The comment portion is prepare for non-type argument.

VI. Comparison

① Argument approach has less execution time. Constructor approach uses heap memory managed by new and delete, while expression argument uses the memory stack maintained for automatic variables.

② Argument approach costs more resource. For example

                           NArray<int,7> one;

                           NArray<int,8> two;

generate two separate class declarations. But

                                  DArray<int> one(7);

                              DArray<int> two(8);

generate just one separate declaration.

③ Constructor approach is more versatile. Because its array size is stored as a class member. So that, for example, we can assignment from an array of one size to an array of another size or to define a function to resize the array.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值