c++primer第十四章代码重用

包含对象成员的类

包含:私有部分有一个类。

使用模板类,声明对象时必须指定具体的数据类型。

范例:

#ifndef STUDENTC_H_
#define STUDENTC_H_
#include <iostream>
#include <string>
#include <valarray>
class Student
{
private:
    typedef std::valarray<double> ArrayDb;
    std::string name; // contained object
    ArrayDb scores;
    // contained object
    //  private method for scores output
    std::ostream &arr_out(std::ostream &os) const;

public:
    Student() : name("Null Student"), scores() {}
    Student(const std::string &s)
        : name(s), scores() {}
    explicit Student(int n) : name("Nully"), scores(n) {}
    Student(const std::string &s, int n)
        : name(s), scores(n) {}
    Student(const std::string &s, const ArrayDb &a)
        : name(s), scores(a) {}
    Student(const char *str, const double *pd, int n)
        : name(str), scores(pd, n) {}
    ~Student() {}

    double Average() const;
    const std::string &Name() const;
    double &operator[](int i);
    double operator[](int i) const;

    // friends
    // input
    friend std::istream &operator>>(std::istream &is, Student &stu);
    // 1 word
    friend std::istream &getline(std::istream &is, Student &stu); // output
    // 1 line
    friend std::ostream &operator<<(std::ostream &os, const Student &stu);
};
#endif

类定义中包括:

可以在代码中使用ArrayDb,而不是std::valarray <double>.

typedef放在类定义的私有部分意味着可以Student类的实现中使用它,但是在类外面不能使用。

其中的--个构造函数使用了关键字explicit:

在上述构造函数中,第一个参数表示数组的元素个数,而不是数组中的值,因此将一个构造函数用作int 到Student 的转换函数是没有意义的,所以使用 explicit 关闭隐式转换。如果省略该关键字,则可以编写如下所示的代码:

防止出现手误的错误。

初始化被包含的对象

对于继承的对象,构造函数在成员初始化列表中使用类名来调用特定的基类构造函数。对于成员对象构造函数则使用成员名。例如,最后一个构造函数:

因为该构造函数初始化的是成员对象,而不是继承的对象,所以在初始化列表中使用的是成员名,而不是类名。初始化列表中的每一项都调用与之匹配的构造函数,即name(str)调用String(const   char*)构造函数,scores(pd,n)调用ArrayDb(const double*,int)构造函数。

使用被包含对象的接口

被包含的对象的接口不是公有的,但是可以在类方法中使用。

上述代码定义了可由 Student对象调用的方法,该方法内部使用了valarray的方法size()和sumO)。这是因为 scores是一个 valarray 对象,所以它可以调用 valarray 类的成员函数。简而言之,Student对象调用Student 的方法,而后者使用被包含的valarray 对象来调用 valarray 类的方法。

同样可以定义友元函数:

注意,operator<<(ostream& os,const Student&stu)必须是 Student 类的友元函数,这样才能访问 name 成员。另一种方法是,在该函数中使用公有方法Name(),而不是私有数据成员name。

因为 stu.name 是一个 string对象,所以它将调用 operatot<<(ostream&,conststring&)函数,该函数位于 string 类中。

#include "studentc.h"
using std::endl;
using std::istream;
using std::ostream;
using std::string;

// public methods
double Student::Average() const
{
    if (scores.size() > 0)
        return scores.sum() / scores.size();
    else
        return 0;
}

const string &Student::Name() const
{
    return name;
}

double &Student::operator[](int i)
{
    return scores[i];
}

double Student::operator[](int i) const
{
    return scores[i];
}

// private method
ostream &Student::arr_out(ostream &os) const
{
    int i;
    int lim = scores.size();
    if (lim > 0)
    {
        for (i = 0; i < lim; i++)
        {
            os << scores[i] << " ";
            if (i % 5 == 4)
                os << endl;
        }

        if (i % 5 != 0)
            os << endl;
    }

    else
        os << "empty array ";
    return os;
}

// friend
// use string version of operator>>()
istream &operator>>(istream &is, Student &stu)
{
    is >> stu.name;
    return is;
}

// use string friend getline(ostream &,const string &)
istream &getline(istream &is, Student &stu)
{
    getline(is, stu.name);
    return is;
}

// use string version of operator<<()
ostream &operator<<(ostream &os, const Student &stu)
{
    os << "Scores for " << stu.name << ":\n";
    stu.arr_out(os); // use private method for scores
    return os;
}

使用新的student类

#include <iostream>
#include "studentc.h"
using std::cin;
using std::cout;
using std::endl;
void set(Student &sa, int n);
const int pupils = 3;
const int quizzes = 5;

int main()
{
    Student ada[pupils] = {Student(quizzes), Student(quizzes), Student(quizzes)};
    int i;
    for (i = 0; i < pupils; ++i)
        set(ada[i], quizzes);
    cout << "\nStudent ist:\n";
    for (i = 0; i < pupils; ++i)
        cout << ada[i].Name() << endl;
    cout << "\nResults:";
    for (i = 0; i < pupils; ++i)
    {
        cout << endl
             << ada[i];
        cout << "average: " << ada[i].Average() << endl;
    }

    cout << "Done.\n";
    return 0;
}
void set(Student &sa, int n)
{
    cout << "Please enter the student's name:";
    getline(cin, sa);
    cout << "Please enter " << n << " quiz scores:\n";
    for (int i = 0; i < n; i++)
        cin >> sa[i];
    while (cin.get() != '\n')
        continue;
}

运行结果

私有继承

私有继承是has-a关系

公有继承是is-a关系

私有继承关键词private

区别是省略了显式对象名称,直接在内联函数中使用了类名。

对于对象中的对象

私有继承可以使用类名和作用域解析符来调用基类的方法。

使用强制类型转换访问基类对象

#ifndef STUDENTI_H_
#define STUDENTI_H_
#include <iostream>
#include <string>
#include <valarray>
class Student : private std::string, private std::valarray<double>
{
private:
    typedef std::valarray<double> ArrayDb;

    // contained object
    //  private method for scores output
    std::ostream &arr_out(std::ostream &os) const;

public:
    Student() : std::string("Null Student"), ArrayDb() {}
    Student(const std::string &s)
        : std::string(s), ArrayDb() {}
    explicit Student(int n) : std::string("Nully"), ArrayDb(n) {}
    Student(const std::string &s, int n)
        : std::string(s), ArrayDb(n) {}
    Student(const std::string &s, const ArrayDb &a)
        : std::string(s), ArrayDb(a) {}
    Student(const char *str, const double *pd, int n)
        : std::string(str), ArrayDb(pd, n) {}
    ~Student() {}

    double Average() const;
    const std::string &Name() const;
    double &operator[](int i);
    double operator[](int i) const;

    // friends
    // input
    friend std::istream &operator>>(std::istream &is, Student &stu);
    // 1 word
    friend std::istream &getline(std::istream &is, Student &stu); // output
    // 1 line
    friend std::ostream &operator<<(std::ostream &os, const Student &stu);
};
#endif
#include "studenti.h"
using std::endl;
using std::istream;
using std::ostream;
using std::string;

// public methods
double Student::Average() const
{
    if (ArrayDb::size() > 0)
        return ArrayDb::sum() / ArrayDb::size();
    else
        return 0;
}

const string &Student::Name() const
{
    return (const string &)*this;
}

double &Student::operator[](int i)
{
    return ArrayDb::operator[](i);
}

double Student::operator[](int i) const
{
    return ArrayDb::operator[](i);
}

// private method
ostream &Student::arr_out(ostream &os) const
{
    int i;
    int lim = ArrayDb::size();
    if (lim > 0)
    {
        for (i = 0; i < lim; i++)
        {
            os << ArrayDb::operator[](i) << " ";
            if (i % 5 == 4)
                os << endl;
        }

        if (i % 5 != 0)
            os << endl;
    }

    else
        os << "empty array ";
    return os;
}

// friend
// use string version of operator>>()
istream &operator>>(istream &is, Student &stu)
{
    is >> (string &)stu;
    return is;
}

// use string friend getline(ostream &,const string &)
istream &getline(istream &is, Student &stu)
{
    getline(is, (string &)stu);
    return is;
}

// use string version of operator<<()
ostream &operator<<(ostream &os, const Student &stu)
{
    os << "ArrayDb::operator[] for " << (const string &)stu << ":\n";
    stu.arr_out(os); // use private method for ArrayDb::operator[]
    return os;
}

同样的程序文件

#include <iostream>
#include "studenti.h"
using std::cin;
using std::cout;
using std::endl;
void set(Student &sa, int n);
const int pupils = 3;
const int quizzes = 5;

int main()
{
    Student ada[pupils] = {Student(quizzes), Student(quizzes), Student(quizzes)};
    int i;
    for (i = 0; i < pupils; ++i)
        set(ada[i], quizzes);
    cout << "\nStudent ist:\n";
    for (i = 0; i < pupils; ++i)
        cout << ada[i].Name() << endl;
    cout << "\nResults:";
    for (i = 0; i < pupils; ++i)
    {
        cout << endl
             << ada[i];
        cout << "average: " << ada[i].Average() << endl;
    }

    cout << "Done.\n";
    return 0;
}
void set(Student &sa, int n)
{
    cout << "Please enter the student's name:";
    getline(cin, sa);
    cout << "Please enter " << n << " quiz scores:\n";
    for (int i = 0; i < n; i++)
        cin >> sa[i];
    while (cin.get() != '\n')
        continue;
}

结果和之前相同

包含和私有继承的选择

 多重继承

多重继承(MI)表示有多个直接基类的类。

MI的问题:

从两个不同的基类继承同名方法:

#ifndef WORKER0_H_
#define WORKER0_H_
#include <string>

class Worker // an abstract base class
{
private:
    std::string fullname;
    long id;

public:
    Worker() : fullname("no one"), id(0L) {}
    Worker(const std::string &s, long n) : fullname(s), id(n) {}
    virtual ~Worker() = 0; // pure virtual destructor
    virtual void Set();
    virtual void Show() const;
};

class Waiter : public Worker
{
private:
    int panache;

public:
    Waiter() : Worker(), panache(0) {}
    Waiter(const std::string &s, long n, int p = 0)
        : Worker(s, n), panache(p) {}
    Waiter(const Worker &wk, int p = 0) : Worker(wk), panache(p) {}
    void Set();
    void Show() const;
};
class Singer : public Worker
{
protected:
    enum
    {
        other,
        alto,
        contralto,
        soprano,
        bass,
        baritone,
        tenor
    };
    enum
    {
        Vtypes = 7
    };

private:
    static char *pv[Vtypes];
    int voice;

public:
    Singer() : Worker(), voice(other) {}
    Singer(const std::string &s, long n, int v = other)
        : Worker(s, n), voice(v) {}
    Singer(const Worker &wk, int v = other)
        : Worker(wk), voice(v) {}
    void Set();
    void Show() const;
};
#endif
#include "worker0.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
// Worker methods

// must implement virtual destructor,even if pure
Worker::~Worker() {}
void Worker::Set()
{
    cout << "Enter worker's name: ";
    getline(cin, fullname);
    cout << "Enter worker's ID:";
    cin >> id;
    while (cin.get() != '\n')
        continue;
}
void Worker::Show() const
{
    cout << "Name:" << fullname << "\n";
    cout << "Employee ID:" << id << "\n";
}

// Waiter methods
void Waiter::Set()
{
    Worker::Set();
    cout << "Enter waiter's panache rating:";
    cin >> panache;
    while (cin.get() != '\n')
        continue;
}
void Waiter::Show() const
{
    cout << "Category: waiter\n";
    Worker::Show();
    cout << "Panache rating:" << panache << "\n";
}

// Singer methods
char *Singer::pv[] = {"other", "alto", "contralto",
                      "soprano", "bass", "baritone", "tenor"};
void Singer::Set()
{
    Worker::Set();
    cout << "Enter number for singer's vocal range:\n";
    int i;
    for (i = 0; i < Vtypes; i++)
    {
        cout << i << ":" << pv[i] << "  ";
        if (i % 4 == 3)
            cout << endl;
    }

    if (i % 4 != 0)
        cout << endl;
    cin >> voice;
    while (cin.get() != '\n')
        continue;
}

void Singer::Show() const
{
    cout << "Category: singer \n";
    Worker::Show();
    cout << "Vocal range: " << pv[voice] << endl;
}

#include <iostream>
#include "worker0.h"
const int LIM = 4;
int main()
{
    Waiter bob("Bob Apple", 314L, 5);
    Singer bev("Beverly Hills", 522L, 3);
    Waiter w_temp;

    Singer s_temp;
    Worker *pw[LIM] = {&bob, &bev, &w_temp, &s_temp};
    int i;
    for (i = 2; i < LIM; i++)
        pw[i]->Set();
    for (i = 0; i < LIM; i++)
    {
        pw[i]->Show();
        std::cout << std::endl;
    }

    return 0;
}

在祖先相同时,使用 MI必须引入虚基类,并修改构造函数初始化列表的规则。

修改后的代码

#ifndef WORKERMI_H_
#define WORKERMI_H_
#include <string>

class Worker // an abstract base class
{
private:
    std::string fullname;
    long id;

protected:
    virtual void Data() const;
    virtual void Get();

public:
    Worker() : fullname("no one"), id(0L) {}
    Worker(const std::string &s, long n) : fullname(s), id(n) {}
    virtual ~Worker() = 0; // pure virtual destructor
    virtual void Set();
    virtual void Show() const;
};

class Waiter : virtual public Worker
{
private:
    int panache;

protected:
    virtual void Data() const;
    virtual void Get();

public:
    Waiter() : Worker(), panache(0) {}
    Waiter(const std::string &s, long n, int p = 0)
        : Worker(s, n), panache(p) {}
    Waiter(const Worker &wk, int p = 0) : Worker(wk), panache(p) {}
    void Set();
    void Show() const;
};
class Singer : virtual public Worker
{
protected:
    enum
    {
        other,
        alto,
        contralto,
        soprano,
        bass,
        baritone,
        tenor
    };
    enum
    {
        Vtypes = 7
    };

protected:
    virtual void Data() const;
    virtual void Get();

private:
    static char *pv[Vtypes];
    int voice;

public:
    Singer() : Worker(), voice(other) {}
    Singer(const std::string &s, long n, int v = other)
        : Worker(s, n), voice(v) {}
    Singer(const Worker &wk, int v = other)
        : Worker(wk), voice(v) {}
    void Set();
    void Show() const;
};

// multiple inheritance
class SingingWaiter : public Singer, public Waiter
{
protected:
    void Data() const;
    void Get();

public:
    SingingWaiter() {};
    SingingWaiter(const std::string &s, long n, int p = 0,
                  int v = other) : Worker(s, n), Waiter(s, n, p), Singer(s, n, v) {}
    SingingWaiter(const Worker &wk, int p = 0, int v = other)
        : Worker(wk), Waiter(wk, p), Singer(wk, v) {}
    SingingWaiter(const Waiter &wt, int v = other)
        : Worker(wt), Waiter(wt), Singer(wt, v) {}
    SingingWaiter(const Singer &wt, int p = 0)
        : Worker(wt), Waiter(wt, p), Singer(wt) {}
    void Set();
    void Show() const;
};

#endif

#include "workermi.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
// Worker methods

// must implement virtual destructor,even if pure
Worker::~Worker() {}

// protect methods
void Worker::Data() const
{
    cout << "Name: " << fullname << endl;
    cout << "Employee ID:" << id << endl;
}

void Worker::Get()
{
    getline(cin, fullname);
    cout << "Enter worker's ID:";
    cin >> id;
    while ((cin.get() != '\n'))
    {
        continue;
    }
}
void Worker::Set()
{
    cout << "Enter worker's name: ";
    getline(cin, fullname);
    Worker::Get();
    Get();
}
void Worker::Show() const
{
    cout << "Category: waiter\n";
    Worker::Data();
    Data();
}
// Waiter methods
void Waiter::Set()
{
    cout << "Enter waiter's name:";
    Worker::Get();
    Get();
}

void Waiter::Show() const
{
    cout << "Category: waiter\n";
    Worker::Data();
    Data();
}

// protect method
void Waiter::Data() const
{
    cout << "Panache rating:" << panache << endl;
}

void Waiter::Get()
{
    cout << "Enter waiter's panache rating:";
    cin >> panache;
    while (cin.get() != '\n')
        continue;
}

// Singer methods
char *Singer::pv[] = {"other", "alto", "contralto",
                      "soprano", "bass", "baritone", "tenor"};
void Singer::Set()
{
    cout << "Enter singer's name\n";
    Worker::Get();
    Get();
}

void Singer::Show() const
{
    cout << "Category: singer \n";
    Worker::Data();
    Data();
}

// protect methods
void Singer::Data() const
{
    cout << "Vocal range: " << pv[voice] << endl;
}

void Singer::Get()
{

    cout << "Enter number for singer's vocal range:\n";
    int i;
    for (i = 0; i < Vtypes; i++)
    {
        cout << i << ":" << pv[i] << "  ";
        if (i % 4 == 3)
            cout << endl;
    }

    if (i % 4 != 0)
        cout << endl;
    cin >> voice;
    while (cin.get() != '\n')
        continue;
}

// SingerWaiter methods

void SingingWaiter::Data() const
{
    Singer::Data();
    Waiter::Data();
}

void SingingWaiter::Get()
{
    Waiter::Get();
    Singer::Get();
}

void SingingWaiter::Set()
{
    cout << "Enter singing waiter's name: ";
    Worker::Get();
    Get();
}

void SingingWaiter::Show() const
{
    cout << "Category:singing waiter\n";
    Worker::Data();
    Data();
}
#include <iostream>
#include <cstring>
#include "workermi.h"
const int SIZE = 5;
int main()
{
    using std::cin;
    using std::cout;
    using std::endl;
    using std::strchr;
    Worker *lolas[SIZE];
    int ct;
    for (ct = 0; ct < SIZE; ct++)
    {
        char choice;
        cout << "Enter the employee category:\n"
             << "w:waiter s:singer "
             << "t:singing waiter q: quit\n";
        cin >> choice;
        while (strchr("wstq", choice) == NULL)
        {
            cout << "Please enteraw,s,t,or g:";
            cin >> choice;
        }

        if (choice == 'q')
            break;
        switch (choice)
        {
        case 'w':
            lolas[ct] = new Waiter;
            break;
        case 's':
            lolas[ct] = new Singer;
            break;
        case 't':
            lolas[ct] = new SingingWaiter;
            break;
        }

        cin.get();
        lolas[ct]->Set();
    }

    cout << "\nHere is your staff:\n";
    int i;
    for (i = 0; i < ct; i++)
    {
        cout << endl;
        lolas[i]->Show();
    }

    for (i = 0; i < ct; i++)
        delete lolas[i];
    cout << "Bye.\n";
    return 0;
}

类模板 

定义类模板

对于下列类

模板类的开头

template <class Type>

同时将所有的Typedef 改成Type

#ifndef STACKTP_H_
#define STACKTP_H_

template <class Type>
class Stack
{
private:
    enum
    {
        MAX = 10
    };               // constant specific to class
    Type items[MAX]; // holds stack items
    int top;
    // index for top stack item
public:
    Stack();
    bool isempty();
    bool isfull();
    bool push(const Type &item); // add item to stack
    bool pop(Type &item);
};
// pop top into item
template <class Type>
Stack<Type>::Stack()
{
    top = 0;
}
template <class Type>
bool Stack<Type>::isempty()
{
    return top == 0;
}
template <class Type>
bool Stack<Type>::isfull()
{
    return top == MAX;
}
template <class Type>
bool Stack<Type>::push(const Type &item)
{
    if (top < MAX)
    {
        items[top++] = item;
        return true;
    }
    else
        return false;
}
template <class Type>
bool Stack<Type>::pop(Type &item)
{
    if (top > 0)
    {
        item = items[--top];
        return true;
    }
    else
        return false;
}

#endif

使用模板类

#include <iostream>
#include <string>
#include <cctype>
#include "stacktp.h"
using std::cin;
using std::cout;
int main()
{

    Stack<std::string> st;
    char ch;
    std::string po;
    cout << "Please enter A to add a purchase order, \n"
         << "P to process a PO, or Q to quit.\n";
    while (cin >> ch && toupper(ch) != 'Q')
    {
        while (cin.get() != '\n')
            continue;
        if (!isalpha(ch))
        {
            cout << '\a';
            continue;
        }
        switch (ch)
        {
        case 'A':
        case 'a':
            cout << "Enter a PO number to add: ";
            cin >> po;
            if (st.isfull())
                cout << "stack already full\n";
            else
                st.push(po);
            break;
        case 'P':
        case 'p':
            if (st.isempty())
                cout << "stack already empty\n";
            else
            {
                st.pop(po);
                cout << "PO #" << po << " popped\n";
            }
            break;
        }
        cout << "Please enter A to add a purchase order, \n"
             << "P to process a PO, or Q to quit. \n";
    }
    cout << "Bye\n";
    return 0;
}

只在程序中包含模板不能生成模板类,必须要求实例化。

指针堆栈

使用指针堆栈需要使用指针数组不然容易出错。

#ifndef STACKTP1_H_
#define STACKTP1_H_

template <class Type>
class Stack
{
private:
    enum
    {
        SIZE = 10
    };
    int stacksize;
    // constant specific to class
    Type *items; // holds stack items
    int top;
    // index for top stack item
public:
    explicit Stack(int ss = SIZE);
    Stack(const Stack &st);
    ~Stack() { delete[] items; }
    bool isempty() { return top == 0; }
    bool isfull() { return top == stacksize; }
    bool push(const Type &item); // add item to stack
    bool pop(Type &item);
    Stack &operator=(const Stack &st);
};

template <class Type>
Stack<Type>::Stack(int ss) : stacksize(ss), top(0)
{
    items = new Type[stacksize];
}

template <class Type>
Stack<Type>::Stack(const Stack &st)
{
    stacksize = st.stacksize;
    top = st.top;
    items = new Type[stacksize];
    for (int i = 0; i < top; i++)
        items[i] = st.items[i];
}
template <class Type>
bool Stack<Type>::push(const Type &item)
{
    if (top < stacksize)
    {
        items[top++] = item;
        return true;
    }
    else
        return false;
}
template <class Type>
bool Stack<Type>::pop(Type &item)
{
    if (top > 0)
    {
        item = items[--top];
        return true;
    }
    else
        return false;
}
template <class Type>
Stack<Type> &Stack<Type>::operator=(const Stack<Type> &st)
{
    if (this == &st)
        return *this;
    delete[] items;
    stacksize = st.stacksize;
    top = st.top;
    items = new Type[stacksize];
    for (int i = 0; i < top; i++)
        items[i] = st.items[i];
    return *this;
}
#endif
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "stacktp1.h"
const int Num = 10;
int main()
{
    std::srand(std::time(0));
    // randomize rand()
    std::cout << "Please enter stack size:";
    int stacksize;
    std::cin >> stacksize;
    // create an empty stack with stacksize slots
    Stack<const char *> st(stacksize);
    // int basket
    const char *in[Num] = {
        "1:Hank Gilgamesh",
        "2:Kiki Ishtar",
        "3:Betty Rocker",
        "4:Ian Flagranti",
        "5:Wolfgang Kibble",
        "6: Portia Koop"
        "7:Joy Almondo",
        "8:Xaverie Paprika",
        "9:Juan Moore",
        "10:Misha Mache"}; // out basket
    const char *out[Num];
    int processed = 0;
    int nextin = 0;
    while (processed < Num)
    {
        if (st.isempty())
            st.push(in[nextin++]);
        else if (st.isfull())
            st.pop(out[processed++]); // 50-50 chance
        else if (std::rand() % 2 && nextin < Num)
            st.push(in[nextin++]);
        else
            st.pop(out[processed++]);
    }
    for (int i = 0; i < Num; i++)
        std::cout << out[i] << std::endl;
    std::cout << "Bye\n";
    return 0;
}

具有随机特性。

数组模板范例和非类型参数

首先介绍一个允许指定数组大小的简单数组模板。一种方法是在类中使用动态数组和构造函数参数来提供元素数目,最后一个版本的 Stack 模板采用这种方法。另一种方法是使用模板参数来提供常规数组的大小,

#ifndef ARRAYTP_H_
#define ARRAYTP_H_
#include <iostream>
#include <cstdlib>
template <class T, int n>
class ArrayTP
{
private:
    T ar[n];

public:
    ArrayTP() {};
    explicit ArrayTP(const T &v);
    virtual T &operator[](int i);
    virtual T operator[](int i) const;
};
template <class T, int n>
ArrayTP<T, n>::ArrayTP(const T &v)
{
    for (int i = 0; i < n; i++)
        ar[i] = v;
}

template <class T, int n>
T &ArrayTP<T, n>::operator[](int i)
{
    if (i < 0 || i >= n)
    {
        std::cerr << "Error in array limits:" << i
                  << " is out of range\n";
        std::exit(EXIT_FAILURE);
    }

    return ar[i];
}

template <class T, int n>
T ArrayTP<T, n>::operator[](int i) const
{
    if (i < 0 || i >= n)
    {
        std::cerr << "Error in array limits:" << i
                  << " is out of range\n";
        std::exit(EXIT_FAILURE);
    }

    return ar[i];
}

#endif

递归使用模板

#include <iostream>
#include "arraytp.h"
int main(void)
{
    using std::cout;
    using std::endl;
    ArrayTP<int, 10> sums;
    ArrayTP<double, 10> aves;
    ArrayTP<ArrayTP<int, 5>, 10> twodee;

    int i, j;

    for (i = 0; i < 10; i++)
    {
        sums[i] = 0;
        for (j = 0; j < 5; j++)
        {
            twodee[i][j] = (i + 1) * (j + 1);
            sums[i] += twodee[i][j];
        }

        aves[i] = (double)sums[i] / 10;
    }

    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < 5; j++)
        {
            cout.width(2);
            cout << twodee[i][j] << ' ';
        }

        cout << ":sum =";
        cout.width(3);
        cout << sums[i] << ",average=" << aves[i] << endl;
    }

    cout << "Done.\n";
    return 0;
}

使用多个类型参数

// pairs.cpp--defining and using a Pair template
#include <iostream>
#include <string>
template <class T1, class T2>
class Pair
{
private:
    T1 a;
    T2 b;

public:
    T1 &first();
    T2 &second();
    T1 first() const { return a; }
    T2 second() const { return b; }
    Pair(const T1 &aval, const T2 &bval) : a(aval), b(bval) {}
    Pair() {}
};
template <class T1, class T2>
T1 &Pair<T1, T2>::first()
{
    return a;
}
template <class Tl, class T2>
T2 &Pair<Tl, T2>::second()
{
    return b;
}
int main()
{
    using std::cout;
    using std::endl;
    using std::string;
    Pair<string, int> ratings[4] =
        {Pair<string, int>("The Purple Duke", 5),
         Pair<string, int>("Jake's Frisco Al Fresco", 4),
         Pair<string, int>("Mont Souffle", 5),
         Pair<string, int>("Gertie's Eats", 3)};
    int joints = sizeof(ratings) / sizeof(Pair<string, int>);

    cout << "Rating:\t Eatery\n";
    for (int i = 0; i < joints; i++)
        cout << ratings[i].second() << ":\t"
             << ratings[i].first() << endl;
    cout << " Oops !Revised rating :\n ";
    ratings[3].first() = " Gertie's Fab Eat";
    ratings[3].second() = 6;
    cout << ratings[3].second() << ":\t"
         << ratings[3].first() << endl;
    return 0;
}

模板的具体化

隐式具体化

显式实例化

template class ArrayTP<string,100>;

显式具体化(待补充)

部分具体化(待补充)

成员模板

模板可用作结构,类或模板类的成员。

下列代码实现了模板的嵌套

#include <iostream>
using std::cout;
using std::endl;

template <typename T>
class beta
{
private:
    template <typename V> // nested template class member
    class hold
    {
    private:
        V val;

    public:
        hold(V v = 0) : val(v) {}
        void show() const { cout << val << endl; }
        V Value() const { return val; }
    };

    hold<T> q;
    hold<int> n;

public:
    // template object// template object
    beta(T t, int i) : q(t), n(i) {}
    template <typename U> // template method
    U blab(U u, T t)
    {
        return (n.Value() + q.Value()) * u / t;
    }
    void Show() const
    {
        q.show();
        n.show();
    }
};
int main()
{
    beta<double> guy(3.5, 3);
    guy.Show();
    cout << guy.blab(10, 2.3) << endl;
    cout << "Done\n";
    return 0;
}

更改代码

将模板用作参数

下列代码将模板作为参数

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

template <template <typename T> class Thing>
class Crab
{1.
private:
    Thing<int> s1;
    Thing<double> s2;

public:
    Crab() {};
    bool push(int a, double x) { return s1.push(a) && s2.push(x); }
    bool pop(int &a, double &x) { return s1.pop(a) && s2.pop(x); }
};

int main()
{
    using std::cin;
    using std::cout;
    using std::endl;
    Crab<Stack> nebula;
    int ni;
    double nb;

    cout << "Enter int double pairs, such as 4 3.5 (0 0 to be end): \n";
    while (cin >> ni >> nb && ni > 0 && nb > 0)
    {
        if (!nebula.push(ni, nb))
            break;
    }
    while (nebula.pop(ni, nb))
        cout << ni << ", " << nb << endl;
    cout << "Done.\n";
    return 0;
}

模板类和友元

模板的友元分类

  • 非模板友元
  • 约束模板友元,友元的类型取决于类被实例化的类型
  • 非约束模板友元,友元的所有具体化都是类的每一个具体化的友元。

 模板类的非模板友元函数

#include <iostream>
using std::cout;
using std::endl;
template <typename T>
class HasFriend
{
private:
    T item;
    static int ct;

public:
    HasFriend(const T &i) : item(i) { ct++; }
    ~HasFriend() { ct--; };
    friend void counts();
    friend void reports(HasFriend<T> &); // template parameter
};

// specialization
template <typename T>
int HasFriend<T>::ct = 0;

void counts()
{
    cout << "int count: " << HasFriend<int>::ct << "; ";
    cout << "double count: " << HasFriend<double>::ct << endl;
}

void reports(HasFriend<int> &hf)
{
    cout << "HasFriend<int>: " << hf.item << endl;
}
void reports(HasFriend<double> &hf)
{
    cout << "HasFriend<double>: " << hf.item << endl;
}

int main()
{
    cout << "No objects declared: ";
    counts();
    HasFriend<int> hfi1(10);
    cout << "After fhi1 declared: ";
    counts();
    HasFriend<int> hfi2(20);
    cout << "After fhi2 declared: ";
    counts();
    HasFriend<double> hfi3(10.5);
    cout << "After hfdb declared: ";
    counts();
    reports(hfi1);
    reports(hfi2);
    reports(hfi3);

    return 0;
}

程序说明:

定义了模板参数:

具体化:

 

模板类的约束模板友元函数

#include <iostream>
using std::cout;
using std::endl;
// template prototypes
template <typename T>
void counts();
template <typename T>
void reports(T &);

// template class
template <typename TT>
class HasFriendT
{
private:
    TT item;
    static int ct;

public:
    HasFriendT(const TT &i) : item(i) { ct++; }
    ~HasFriendT() { ct--; };
    friend void counts<TT>();
    friend void reports<>(HasFriendT<TT> &); // template parameter
};

// specialization
template <typename T>
int HasFriendT<T>::ct = 0;

template <typename T>
void counts()
{
    cout << "template size: " << sizeof(HasFriendT<T>) << "; ";
    cout << "template counts: " << HasFriendT<T>::ct << endl;
}

template <typename T>
void reports(T &hf)
{
    cout << hf.item << endl;
}

int main()
{

    counts<int>();
    HasFriendT<int> hfi1(10);
    HasFriendT<int> hfi2(20);
    HasFriendT<double> hfi3(10.5);
    reports(hfi1);
    reports(hfi2);
    reports(hfi3);
    cout << "counts<int>() output: \n";
    counts<int>();
    cout << "counts<double>() output: \n";
    counts<double>();

    return 0;
}

这种情况每个T类型都有自己的count函数

因为有定义:

模板类的非约束模板友元函数

约束模板友元函数是在类外面声明的模板的具体化。int 类具体化获得int 函数具体化,依此类推。通过在类内部声明模板,可以创建非约束友元函数,即每个函数具体化都是每个类具体化的友元。对于非约束友元,友元模板类型参数与模板类类型参数是不同的:

#include <iostream>
using std::cout;
using std::endl;

template <typename T>
class ManyFriend
{
private:
    T item;

public:
    ManyFriend(const T &i) : item(i) {}
    template <typename C, typename D>
    friend void show2(C &, D &);
};
template <typename C, typename D>
void show2(C &c, D &d)
{
    cout << c.item << ", " << d.item << endl;
}
int main()
{
    ManyFriend<int> hfi1(10);
    ManyFriend<int> hfi2(20);
    ManyFriend<double> hfdb(10.5);

    cout << "hfi1, hfi2: ";
    show2(hfi1, hfi2);
    cout << "hfdb, hfi2:";
    show2(hfdb, hfi2);

    return 0;
}

其中非约束模板友元函数为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值