当前位置:   article > 正文

C++(12) 模板类、模板继承(严格模式和自由模式)

C++(12) 模板类、模板继承(严格模式和自由模式)

模版类

1. 模版类
#include <iostream>

using namespace std;

/*
当前 Person 类型,声明了连个模版分别对应
    NameType 模版类型,名称可以看出,用于约束成员变量 name 的类型
    AgeType  模版类型,名称可以看出,用于约束成员变量 age 的类型

模版类型充当数据类型占位符,在整个类中,成员变量,成员函数,构造函数都可以使用
*/
template <typename NameType, typename AgeType>
class Person
{
public:
    Person() {}
    Person(NameType name, AgeType age) : name(name), age(age) {}
    Person(const Person & person) : name(person.name), age(person.age) {}
    ~Person() {}

    NameType getName() { return name; }
    void setName(NameType name) { this->name = name; }

    AgeType getAge() { return age; }
    void setAge(AgeType age) { this->age = age; }

private:
    NameType name;
    AgeType age;
};

int main(int argc, char const *argv[])
{
    /*
    Person 类型带有模版修饰,需要在使用之前明确模版对应的具体类型
    模版具备数据类型支持的多样性,同时一旦确定模版类型,严格遵守数据类型一致化原则

    Person 类型如何确定模版对应的具体数据类型
    格式:
    类名<模版对应具体数据类型> * 对象 = new 类型<模版对应具体数据类型>(...);
        Person<NameType, AgeType>
    */

    // p1 明确告知编译器 NameType ==> string AgeType ==> int
    // 在后续的代码中,通过 p1 调用 Person 类内函数按照以上规则完成
    Person<string, int> *p1 = new Person<string, int>();

    p1->setName("布丁");
    p1->setAge(3);

    cout << "Name : " << p1->getName() << ", Age : " << p1->getAge() << endl;

    Person<string, int> *p2 = new Person<string, int>("张三", 14);
    cout << "Name : " << p2->getName() << ", Age : " << p2->getAge() << endl;

    delete p1;
    delete p2;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
2. 模版参数限制

双重限制

  • 限制外部类型
  • 限制模版类型
#include <iostream>

using namespace std;

template <typename DataType, typename MsgType>
class Data
{
public:
    Data() {}
    Data(DataType value, MsgType msg) : value(value), msg(msg) {}
    Data(const Data &data) : value(data.value), msg(data.msg) {}
    ~Data() {}

    DataType getValue() { return value; }
    void setValue(DataType value) { this->value = value; }

    MsgType getMsg() { return msg; }
    void setMsg(MsgType msg) { this->msg = msg; }

private:
    DataType value;
    MsgType msg;
};

/*
当前 test1 函数明确告知调用者,当前所需的参数为 Data
同时限制 Data 中对应的模版类型为 <int, string>
*/
void test1(Data<int, string> *data);

/*
当前 test1 函数明确告知调用者,当前所需的参数为 Data
同时限制 Data 中对应的模版类型为 <double, string>
*/
void test1(Data<double, string> *data);

int main(int argc, char const *argv[])
{
    /*
    双重限制
    */
    Data<int, string> *d1 = new Data<int, string>(10, "别困!");
    Data<double, string> *d2 = new Data<double, string>(3.14, "别困!!");
    Data<char, string> *d3 = new Data<char, string>('G', "遵守数据类型一致化原则");

    test1(d1);
    test1(d2);
    /*
    test1 函数重载操作,所需函数有两种情况
        Data<int, string> *
        Data<double, string> *

    并没有支持
        Data<char, string> * 考虑到双重限制,分别对应外部类型和模版类型
        因此 d3 无法作为函数 test1 的实际参数
        【注意】请遵守数据类型一致化原则
    */
    // test1(d3);

    delete d1;
    delete d2;
    delete d3;

    return 0;
}


void test1(Data<int, string> *data)
{
    cout << "value : " << data->getValue() << ", Msg : " << data->getMsg() << endl;
}

void test1(Data<double, string> *data)
{
    cout << "value : " << data->getValue() << ", Msg : " << data->getMsg() << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
3. 模版继承
3.1 严格模式
#include <iostream>

using namespace std;

/*
类带有模版,同时有子类继承当前类
    1. 自由模式
        子类带有和父类同名声明模版
    2. 严格模式【当前模式】
        子类在继承父类时,直接指定模版的具体类型,不得修改
*/

/*
MyCompare 类
    1. 声明了模版
    2. 声明纯虚函数
    3. MyCompare 是一个抽象类
*/
template <typename T>
class MyCompare
{
public:
    // 纯虚函数,并且使用了类声明的模版
    virtual bool compare(T t1, T t2) = 0;
};
/*
IntCompare 类
    1. 继承了 MyCompare 抽象类
    2. 继承父类的过程中,同时限制了模版对应的具体类型
    3. IntCompare 类没有声明模版

IntCompare 目标是一个【实现类】
    1. 必须实现 Compare 函数
    2. 父类 MyCompare 已经明确限制模版对应的具体类型为 int 类型
    3. IntCompare 目标实现的函数
        bool compare(int t1, int t2)
*/
class IntCompare : public MyCompare<int>
{
public:
    bool compare(int t1, int t2)
    {
        return t1 > t2;
    }
};

int main(int argc, char const *argv[])
{
    /*
    bool compare(long t1, long t2) {...}
        在明确 模版对应的类型为 int 类型,实现上面的函数
        实例化的过程中,会出现报错:
        纯虚拟 函数 "MyCompare<T>::compare [其中 T=int]" 没有强制替代项
    */
    IntCompare * ic = new IntCompare;

    cout << "ret : " << ic->compare(30, 20) << endl; // 1
    cout << "ret : " << ic->compare(10, 20) << endl; // 0

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
3.2 自由模式
#include <iostream>

using namespace std;

/*
类带有模版,同时有子类继承当前类
    1. 自由模式【当前模式】
        子类带有和父类同名声明模版
    2. 妻管严模式
        子类在继承父类时,直接指定模版的具体类型,不得修改
*/

/*
MyCompare 类
    1. 声明了模版
    2. 声明纯虚函数
    3. MyCompare 是一个抽象类
*/
template <typename T>
class BaseHandler
{
public:
    // 纯虚函数,并且使用了类名声明的模版
    virtual void handler(T t) = 0;
};

/*
MyHander 继承抽象类 BaseHandler,同时
    1. 声明和 BaseHandler 同名模版
    2. 当前模版类型尚未明确
    3. 必须实现 void hander(T t) 函数
*/
template <typename T>
class MyHandler : public BaseHandler<T>
{
public:
    void handler(T t)
    {
        cout << "数据情况 : " << t << endl;
    }
};

int main(int argc, char const *argv[])
{
    // 实例化 MyHandler 类对象,需要指定模版对应的具体类型
    MyHandler<string> * m1 = new MyHandler<string>;
    m1->handler("零零零零");

    MyHandler<int> * m2 = new MyHandler<int>;
    m2->handler(14);

    delete m1;
    delete m2;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
4. 模版类的模版函数
#include <iostream>

using namespace std;

template <typename T>
class Test
{
public:
    // 当前函数使用的模版为当前 Test 类声明的模版
    void handler(T t) { cout << "value : " << t << endl; }

    /*
    模版类内的函数,期望可以自定义模版,使用的模版数据形式,约束与当前类不同
    */
    template <typename T2>
    void my(T2 t) { cout << "value : " << t << endl; }
};

int main(int argc, char const *argv[])
{
    Test<string> * test = new Test<string>;

    test->handler("零零零零");

    /*
    my 函数对应的模版类型,由实际参数决定,并不是实例化 Test 类型决定
    */
    test->my(3.14);

    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
5. 返回值类型带有模版
#include <iostream>

using namespace std;

/*
K ==> Key   键
V ==> Value 值
*/
template <typename K, typename V>
class Data
{
public:
    Data() {}
    Data(K key, V value) : key(key), value(value) {}
    Data(const Data & data) : key(data.key), value(data.value) {}
    ~Data() {}

    K getKey() { return key; }
    void setKey(K key) { this->key = key; }

    V getValue() { return value; }
    void setValue(V value) { this->value = value; }

    /*
    友元函数中,重载运算符操作,使用的模版并不是 Data 声明的模版
    而是函数自定义模版,通过实际参数 Data 类型中的模版情况,
    限制当前函数的模版类型

    【满足注意 Data 类型展示数据操作】
    */
    template <typename K1, typename V1>
    friend ostream & operator<<(ostream & o, Data<K1, V1> * data);

private:
    K key;
    V value;
};

template <typename K1, typename V1>
ostream & operator<<(ostream & o, Data<K1, V1> * data)
{
    o << "Key : " << data->getKey() << ", Value : " << data->getValue();
    return o;
}

template <typename K, typename V>
Data<K, V> *getData(K key, V value);

int main(int argc, char const *argv[])
{
    string name = "MY";
    Data<string, int> * data = getData(name, 3);
    cout << data << endl;

    Data<double, int> * data1 = getData(6.18, 9999);
    cout << data1 << endl;

    delete data;
    delete data1;

    return 0;
}

/*
外部函数自定义模版,返回值是 Data 类型,同时
利用当前函数的实际参数对 Data 中模版数据进行
约束限制,模版具体数据情况根据参数具体数据类型确定!
*/
template <typename K, typename V>
Data<K, V> * getData(K key, V value)
{
    return new Data<K, V>(key, value);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/131048
推荐阅读
相关标签
  

闽ICP备14008679号