lecture8 Template Classes + Const Correctness
lecture8 Template Classes + Const Correctness
Classes Recap
“Template Class: A class that is parametrized over some number of types. A class that is comprised of member variables of a general type/types.” 模板类:在一定数量的类型上参数化的类。由通用类型的成员变量组成的类。
“Writing a Template Class: Syntax” 编写模板类:语法
// mypair.h
template<typename First, typename Second> class MyPair{
public:
First getFirst();
Second getSecond();
void setFirst(First f);
void setSecond(Second f);
private:
First first;
Second second;
};
“Use generic typenames as placeholders!” 使用通用类型名称作为占位符!
“Implementing a Template Class: Syntax” 实现模板类:语法
// mypair.cpp
#include "mypair.h"
template<class First, typename Second>
First Mypair<First, Second>::getFirst(){
return first;
}
Template Classes
“Member Types” 成员类型
-
“Sometimes, we need a name for a type that is dependent on our template types”
有时,我们需要一个依赖于我们的模板类型的类型名称
-
Recall: iterators
std::vector<int> a = {1, 2};
std::vector<int>::iterator it = a.begin();
- 在这里
iterator
是vector
的成员类型
“Member Types: Syntax” 成员类型:语法
// vector.h
template<typename T> class vector{
public:
using iterator = T*;
iterator begin();
}
// vector.cpp
typename vector<T>::iterator vector<T>::begin() {}
- 可以在应用代码中使用
using type_name=type
- 当在类接口中使用类型别名时,它会定义一个简洁类型就像
vector::iterator
- 当在应用代码中使用时(比如
main.cpp
)会在范围内为type
创建另一个名字
Const Correctness
“const: keyword indicating a variable, function or parameter can’t be modified” const:关键字,表示变量、函数或参数不能被修改
// student.h
class Student {
public:
std::string getName();
void setName(string name);
int getAge();
void setAge(int age);
private:
std::string name;
std::string state;
int age;
};
// student.cpp
#include "student.h"
std::string Student::getName(){
return name;
}
void Student::setName(string name) {
this->name = name;
}
int Student::getAge() {
return age;
}
void Student::setAge(int age) {
if(age>=0) {
this->age = age;
}
else error("Age cannot be negative!");
}
//main.cpp
std::string stringify(const Student& s) {
return s.getName() + " is " + std::to_string(s.getAge()) + " years old.";
}
// complie error!
- 编译器不知道
getName
和getAge
会改变s - 我们需要保证将以上函数设为
const function
- 将
add
假如函数签名后
// student.h
class Student {
public:
std::string getName() const;
void setName(string name);
int getAge() const;
void setAge(int age);
private:
std::string name;
std::string state;
int age;
};
// student.cpp
#include "student.h"
std::string Student::getName()const{
return name;
}
void Student::setName(string name) {
this->name = name;
}
int Student::getAge() const{
return age;
}
void Student::setAge(int age) {
if(age>=0) {
this->age = age;
}
else error("Age cannot be negative!");
}
“const-interface: All member functions marked const in a class definition. Objects of type const ClassName may only use the const-interface.” const-interface:类定义中标记为 const 的所有成员函数。 const ClassName 类型的对象只能使用 const 接口。
“Making StrVector‘s const-interface” 制作 StrVector 的 const 接口
class StrVector {
public:
using iterator = std::string*;
const size_t kInitialSize = 2;
size_t size();
bool empty();
std::string& at(size_t index);
void insert(size_t pos, const std::string& elem);
void push_back(const std::string& elem);
iterator begin();
iterator end();
}
class StrVector {
public:
using iterator = std::string*;
const size_t kInitialSize = 2;
size_t size() const;
bool empty() const;
std::string& at(size_t index);
const std::string& at(size_t indx) const;
void insert(size_t pos, const std::string& elem);
void push_back(const std::string& elem);
iterator begin();
iterator end();
}
“Should begin() and end() be const?” begin() 和 end() 应该是 const 吗?
void printVec(const StrVector& vec) {
cout<<"{ ";
for(auto it = vec.begin(); it != vec.end(); ++it) {
cout<<*it<<endl;
}
cout<<" }"<<endl;
}
看起来将其设为const
是可行的,但会发生什么错误?
void printVec(const StrVector& vec) {
cout<<"{ ";
for(auto it = vec.begin(); it != vec.end(); ++it) {
*it = "dont mind me modifying a const vector :D";”
}
cout<<" }"<<endl;
}
以上代码会编译通过!因为begin()
和end()
并不会显式改变vec,但是这个itertor
确实可以改变的
“Problem: we need a way to iterate through a const vec just to access it” 问题:我们需要一种方法来迭代 const vec 来访问它(仅限访问与迭代但是不能更改)
“Solution: cbegin() and cend()” 解决方案:cbegin() 和 cend()
class StrVector {
public:
using iterator = std::string*;
using const_iterator = const std::string*;
const size_t kInitialSize = 2;
size_t size() const;
bool empty() const;
std::string& at(size_t index);
const std::string& at(size_t indx) const;
void insert(size_t pos, const std::string& elem);
void push_back(const std::string& elem);
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
}
“Abilities of Iterator Permutations” 迭代器排列的能力
Iterator Type | Increment Iterator? | Change underlying value? |
iterator | Y | Y |
const_iterator | Y | N |
const iterator | N | Y |
const const_iterator | N | N |
可以这么理解:
string*
可以看作数组的头指针即数组
const string*
是将数组声明为常数数组内部不能更改,但是数组迭代可以
const iterator
是将指针所指空间声明常量,不能迭代(会改变指针所指位置)但是可以更改指针空间内存的东西
const const_iterator
是将数组和指针所指地址均视作常量均不能更改
“const iterator vs const_iterator: Nitty Gritty”
using iterator = std::string*;
using const_iterator = const std::string*;
const iterator it_c = vec.begin();//string * const, const ptr to non-const obj
*it_c = "hi"; //OK! it_c is a const pointer to non-const object
it_c++; //not ok! can’t change where a const pointer points!
const_iterator c_it = vec.begin(); //const string*, a non-const ptr to const obj
c_it++; // totally ok! The pointer itself is non-const
*c_it = "hi" // not ok! Can’t change underlying const object
cout << *c_it << endl; //allowed! Can always read a const object, just can't change
//const string * const, const ptr to const obj
const const_iterator c_it_c = vec.begin();
cout << c_it_c << " points to " << *c_it_c << endl; //only reads are allowed!
c_it_c++; //not ok! can’t change where a const pointer points!
*c_it_c = "hi" // not ok! Can’t change underlying const object