08 类模板⚓︎
约 648 个字 71 行代码 预计阅读时间 4 分钟
类模板⚓︎
类模板(template class)是一种类,它将类型作为参数,实际运用时用这些参数来代替实际的类型。
举个:
// template declaration
template <typename T>
class Container
{
public:
Container (T val);
T getValue();
private:
T value;
};
函数模板(template functions)的定义:
#include "Container.h"
template <class T>
Container<T>::Container(T val)
{
this->value = val;
}
template <typename T>
T Container<T>::getValue()
{
return value;
}
在类模板中,如果类的成员函数返回的是类的某个成员变量,返回类型应设为typename ClassName<T1, T2, ...>::member_type
,而不仅仅是 member_type
注意
由于在实例化之前,模板不会给出真正可运行的代码,所以还需要在 .h 文件里#<inlude>
.cpp 文件。
const 的正确使用⚓︎
定义了 Student 类的接口,如下所示:
class Student
{
private:
using String = std::string;
String name;
String state;
int age;
public:
Student(String name, String state, int age);
void setName(String name);
String getName();
String getState();
int getAge();
}
若我们定义了以下函数:
std::string stringify(const Student& s)
{
return s.getName() + " is " + std::to_string(s.getAge()) + " years old.";
}
这会出现编译错误。虽然看起来我们只是用到了对象s
里的一些成员,并没有对成员做什么修改,但是编译器就不知道s
的成员函数(getName()
getAge()
)是否会修改s
的内容,所以编译器认为s
有可能会被修改,因此不能用const
修饰。
如果想要避免报错,就得按照高光部分修改(它们的函数实现也得加上const
class Student
{
private:
using String = std::string;
String name;
String state;
int age;
public:
Student(String name, String state, int age);
void setName(String name);
String getName() const;
String getState();
int getAge() const;
}
上面的例子告诉我们:如果对象用const
修饰,那么它只能和同样被const
修饰的接口交互,这样编译器才敢肯定调用的接口不会修改对象(类)的内容。
事实上,类的成员函数的实现可以同时有常规版和 const
修饰版,两者只相差一个 const
,下面以某个成员函数为例:
int& at(size_t index)
{
return _array[index];
}
int& at(size_t index) const
{
return _array[index];
}
看起来很简单,只要将常规版的内容复制粘贴一遍,之后补个 const
就行,可万一函数定义的代码很长很长,再复制粘贴的话可读性就很差了,因此这里有一个比较巧妙的方法来解决这一问题:使用 const_cast
运算符,格式为 const_cast<target_type> { expression }
,其中 target_type
应为类名。无论函数定义花括号内的主体部分有多少行代码,下面的 const
版本只要在花括号内写一句话就完工了:
int& at(size_t index) const
{
// 先调用一遍 non-const 版,再将它“投射”到 const 版本
return const_cast<IntArray&>(*this).at(value);
}
补充
auto
类型不会自动补上const
和&
,请注意!- 迭代器和
const
的关系:const iterator
:不能让迭代器递增,但是可以解引用或改变它底层的值const_iterator
(iterator
前用const_
修饰,中间没有空格) :可以递增迭代器,但不能解引用或改变它底层的值const const_iterator
:什么都不可以改变
评论区