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