C++泛型编程

发布于:2025-03-15 ⋅ 阅读:(11) ⋅ 点赞:(0)

感谢哔哩哔哩UP”开发者LaoJ“,以下是听课记录~

模板是C++实现泛型编程的手段,同一段代码逻辑可以接受多个类型的参数

无论是函数模板还是类模板,在编码后,需要分文件时,将其声明和定义放进.hpp文件中。不要将声明放.h,定义放.cpp,会报错

一、函数模板

对于函数模板,使用不同的类型对其进行实例化时,会生成多个不同的函数

当没有调用函数模板时,不会被实例化(延迟实例化)

1.1、接受类型参数

#include <iostream>
#include <string>
using namespace std;

template <typename T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
/*允许为特定的数据类型提供定制的实现
 *当类型为int时,调用的是以下实现,而不是函数模板中的实现*/
void Swap(int& a, int& b)
{
	int tmp = a;
	a = 2 * b;
	b = 2 * tmp;
}

int main(void)
{
	int val1 = 10, val2 = 20;
	cout << val1 << " " << val2 << endl;
	/*函数模板有自动推导
	 *Swap<int>(val1, val2)与Swap(val1, val2)等价*/
	Swap<int>(val1, val2);
	cout << val1 << " " << val2 << endl;
	double d1 = 3.14, d2 = 6.78;
	cout << d1 << " " << d2 << endl;
	Swap(d1, d2);
	cout << d1 << " " << d2 << endl;
	return 0;
}

1.2、接受非类型参数作为常量 

#include <iostream>
#include <string>
using namespace std;

template <int N>
void printNTimes(const string& str)
{
	for (int i = 0; i < N; ++i)
		cout << str << endl;
}

int main(void)
{
	string str = "hello world!";
	printNTimes<5>(str);
}

二、类模板

2.1、类模板

类模板的类型参数可以有默认值(默认值从右到左,不能出现右边的没有默认值而左边的有默认值)

类模板没有自动推导的使用方式(在创建类对象时,必须显式说明类型)

/*没有自动推导方式*/
template<typename T1, typename T2>
clase myclass
{
public:
	myclass(T1 name, T2 age) : name(name), age(age) {}
private:
	T1 name;
	T2 age;
};

myclass<string, int> obj("lisi", 20);       //正确
myclass obj("lisi", 20);                    //错误,要显示说明类型


/*默认值*/
template<typename T1, typename T2 = int>    //正确,可以有默认值
template<typename T1 = string, typename T2> //错误,默认值应该从右到左

2.1.1、模板类在调用时,才会被实例化

#include<iostream>
using namespace std;

class me
{
public:
	void showme() {
		cout << "This is me" << endl;
	}
};

template <typename T>
class myclass
{
public:
	void test() {
        T obj;
        obj.showme();   //未定义
    }
};

int main(void)
{
	myclass<me> obj;
	obj.test();
	return 0;
}

2.1.2、在模板类内声明函数,在类外定义函数

#include<iostream>
using namespace std;

class me
{
public:
	void showme() {
		cout << "This is me" << endl;
	}
};

template <typename T>
class myclass
{
public:
	void test();
};

/*函数在类外进行定义*/
template <typename T>
void myclass<T>::test() {
	T obj;
	obj.showme();
}

int main(void)
{
	myclass<me> obj;
	obj.test();
	return 0;
}

2.1.3、当模板类作为函数参数时

#include<iostream>
#include<string>
using namespace std;

template <typename T1, typename T2>
class myclass
{
public:
	myclass(T1 name, T2 age) : name(name), age(age) {}
	void showme() {
		cout << "name:" << name << " " << "age:" << age << endl;
	}
private:
	T1 name;
	T2 age;
};

/*方法一:确定具体的类型传入*/
void func1(myclass<string, int> obj) 
{
	obj.showme();
}

/*方法二:参数模板化*/
template <typename T1, typename T2>
void func2(myclass<T1, T2> obj) 
{
	obj.showme();
}

/*方法三:将类模板化*/
template <typename T>
void func3(T& obj) 
{
	obj.showme();
}

int main(void) 
{
	myclass<string, int> obj("lisi", 20);
	func1(obj);
	func2(obj);
	func2(obj);
	return 0;
}

2.2、类模板与继承

#include <iostream>
using namespace std;

/*基类是模板类*/
template <typename T>
class Base {
public:
    Base(T value) : data(value) {}
    void show() {
        cout << "Base data: " << data << endl;
    }
protected:
    T data;
};

/*情况一:派生类不是模板类*/
//方法一:派生类继承模板基类的特化版本(例如 int)
class DerivedInt : public Base<int> {
public:
    DerivedInt(int value) : Base<int>(value) {}  //在此处,调用了Base<int>类的构造函数
    void display() {
        cout << "DerivedInt data: " << data << endl;
    }
};
//方法二:派生类继承模板基类(仍然是模板)
template <typename T>
class DerivedTemplate : public Base<T> {
public:
    DerivedTemplate(T value) : Base<T>(value) {}
    void display() {
        cout << "DerivedTemplate data: " << this->data << endl;
    }
};

/*情况二:派生类是模板类*/
template <typename T, typename U>
class Derived : public Base<T> {
public:
    Derived(T baseValue, U derivedValue) : Base<T>(baseValue), extraData(derivedValue) {}
    void display() {
        cout << "Base data: " << this->data << ", Derived data: " << extraData << endl;
    }
private:
    U extraData;
};

int main() {
    /*对于情况一*/
    DerivedInt obj1(10);
    obj1.show();
    obj1.display();

    DerivedTemplate<double> obj2(3.14);
    obj2.show();
    obj2.display();

    /*对于情况二*/
    Derived<int, double> obj3(10, 3.14);
    obj3.show();     // 调用基类方法
    obj3.display();  // 调用派生类方法

    return 0;
}

2.3、友元函数与模板类

#include <iostream>
#include <string>
using namespace std;

// 前向声明模板类和函数print
template <typename T1, typename T2>
class Base;
template <typename T1, typename T2>
void print(Base<T1, T2>& obj);

template <typename T1, typename T2>
class Base {
public:
    Base(T1 name, T2 age) : name(name), age(age) {}
    /*在类内定义友元函数*/
    friend void show(Base<T1, T2>& obj) {
        cout << "show:" << endl;
        cout << "name:" << obj.name << " " << "age:" << obj.age << endl;
    }
    friend void print<T1, T2>(Base<T1, T2>& obj);
private:
    T1 name;
    T2 age;
};

/*在类外定义友元函数
 *一、需要向前声明模板类和友元函数
 *二、在类中声明友元函数
 *三、在类外定义友元函数*/
template <typename T1, typename T2>
void print(Base<T1, T2>& obj) {
    cout << "print: " << endl;
    cout << "name:" << obj.name << " " << "age:" << obj.age << endl;
}

int main(void) {
    Base<string, int> obj("lisi", 20);
    show(obj);
    print(obj);
    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到