侯捷C++面向对象编程(下)课程打卡 Day5
1 转换
1.1 转换函数
将当前对象的类型转换成其他类型
- 以operator开头,函数名称为需要转换的类型,无参数
- 前面无需写返回类型,编译器会自动根据函数名称进行补充
- 转换函数中,分子分母都没有改变,所有通常加const\
// class Fraction里的一个成员函数
operator double() const
{
return (double) (m_numerator / m_denominator);
}
Fraction f(3,5);
double d = 4 + f; //编译器自动调用转换函数将f转换为0.6
1.2 non-explicit-one-argument ctor
将其他类型的对象转换为当前类型
one-argument 表示只要一个实参就够了
// non-explicit-one-argument ctor
Fraction(int num, int den = 1)
: m_numerator(num), m_denominator(den) {}
Fraction f(3,5);
Fraction d = f + 4; //编译器调用ctor将4转化为Fraction
1.3 explicit
当上面两个都有转换功能的函数在一起,编译器调用时都可以用,报错
class Fraction
{
public:
Fraction(int num, int den = 1)
: m_numerator(num), m_denominator(den) {}
operator double() const
{
return (double)m_numerator / m_denominator;
}
Fraction operator+(const Fraction& f) const
{
return Fraction(...);
}
private:
int m_numerator; // 分子
int m_denominator; // 分母
};
...
Fraction f(3,5);
Fraction d = f + 4; // [Error] ambiguous
one-argument ctor 加上 explicit
,表示这个 ctor 只能在构造的时候使用,编译器不能拿来进行类型转换了
...
explicit Fraction(int num, int den = 1)
: m_numerator(num), m_denominator(den) {}
...
Fraction f(3,5);
Fraction d = f + 4; // [Error] 4不能从‘double’转化为‘Fraction’
关键字 explicit
主要就在这里运用
2 xxx-like classes
2.1 pointer-like classes
2.1.1 智能指针
- 设计得像指针class,能有更多的功能,包着一个普通指针
- 指针允许的动作,这个类也要有,其中
*
,->
一般都要重载
template <typename T>
class shared_ptr
{
public:
T& operator*() const { return *px; }
T* operator->() const { return px; }
shared_ptr(T* p) : ptr(p) {}
private:
T* px;
long* pn;
};
在使用时,*shared_ptr1
就返回 *px
;
但是 shared_ptr1->
得到的东西会继续用 ->
作用上去,相当于这个->符号用了两次
2.1.2 迭代器
以标准库中的链表迭代器为例,这种智能指针还需要处理 ++
--
等符号
node是迭代器包着的一个真正的指针,其指向
_list_node
- 下图
*ite
的意图是取data
——即一个 Foo 类型的 object - 下图
ite->method
的意图是调用 Foo 中的函数 method
2.2 function-like classes
设计一个class,行为像一个函数
函数行为即 —— xxx()
有一个小括号,所以函数中要有对 ()
进行重载
template <class pair>
struct select1st ... // 这里是继承奇特的Base classes,先不管
{
const typename pair::first_type& // 返回值类型,先不管
operator()(const pair& x) const
{
return x.first;
}
};
...
//像一个函数一样在用这个类
select1st<my_pair> selector;
first_type first_element = selector(example_pair);
//还可以这样写,第一个()在创建临时对象
first_type first_element = select1st<my_pair>()(example_pair);
...
3 模板
3.1 类模板/函数模板
补充:只有模板的尖括号中<>,关键字 typename
和 class
是一样的
3.2 成员模板
它即是模板的一部分,自己又是模板,则称为成员模板
其经常用于构造函数
ctor1 这是默认构造函数的实现;它初始化 first 和 second 分别为 T1 和 T2 类型的默认构造函数生成的默认值
ctor2 这是带参数的构造函数的实现;它接受两个参数 a 和 b,并将它们分别用来初始化 first 和 second 成员变量
ctor3 这是一个==模板构造函数==,接受一个不同类型的 pair 对象作为参数;它允许从一个不同类型的 pair 对象构造当前类型的 pair 对象,在构造过程中,它将源 pair 对象的 first 和 second 成员变量分别赋值给当前对象的成员变量,使其具有一定的灵活性和通用性。
template <class T1, class T2>
struct pair
{
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {} //ctor1
pair(const T1& a, const T2& b) : //ctor2
first(a), second(b) {}
template <class U1, class U2> //ctor3
pair(const pair<U1, U2>& p) :
first(p.first), second(p.second) {}
};
- 例一,可以使用 <鲫鱼,麻雀> 对象来构造一个 <鱼类,鸟类> 的pair
例二,父类指针是可以指向子类的,叫做 up-cast;智能指针也必须可以,所以其构造函数需要为==模板构造函数==
3.3 模板模板参数
即模板中的一个模板参数也为模板,下图黄色高亮部分
- XCLs<string, list> mylist 中即表示:容器 list 是 string 类型的—— 创建一个 string 的链表;Container c; 即表示 list c;
- 但是这样 Container c; 语法过不了,容器 list 后面还有参数,需要用中间框和下面框下一行的代码 —— c++11的内容
注:下面不是模板模板参数
class Sequence = deque<T>` 是有一个初始值,当没指定时就初始为 `deque<T>
在要指定时,如最后一行中的 list<int>
是确切的,不是模板