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” 成员类型

std::vector a = {1, 2};
std::vector::iterator it = a.begin();

  • 在这里iteratorvector 的成员类型

“Member Types: Syntax” 成员类型:语法

// vector.h
template class vector{
public:
using iterator = T*;

iterator begin();
}

// vector.cpp
typename vector::iterator vector::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 😄";”
}
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

posted @ 2024-05-05 23:57  viewoverlook  阅读(35)  评论(0)    收藏  举报