lecture8 Template Classes + Const Correctness

viewoverlook發表於2024-05-05

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” 成員型別

std::vector<int> a = {1, 2};
std::vector<int>::iterator it = a.begin();
  • 在這裡iteratorvector 的成員型別

“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() {}

“Aside: Type Aliases” 型別別名

  • 可以在應用程式碼中使用using type_name=type
  • 當在類介面中使用型別別名時,它會定義一個簡潔型別就像vector::iterator
  • 當在應用程式碼中使用時(比如main.cpp)會在範圍內為type 建立另一個名字

Const Correctness

“const: keyword indicating a variable, function or parameter can’t be modified” const:關鍵字,表示變數、函式或引數不能被修改

“Recall: Student class”

// 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!");
}

“Using a const Student”

//main.cpp
std::string stringify(const Student& s) {
	return s.getName() + " is " + std::to_string(s.getAge()) + " years old.";
}
// complie error!
  • 編譯器不知道getNamegetAge 會改變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

相關文章