第四周内容比较的散,大纲如下
- Conversion Function
- non-explicit one argument constructor
- pointer-like classes
- Function-like classes
- namespace经验谈
- class template
- Function Template
- Member Template
- specialization
- 模板偏特化
- 模板模板参数
- 关于C++标准库
- 三个主题
- Reference
- 复合&继承关系下的构造和析构
第四周的内容也是相对零零散散,有虚函数指针vptr,虚函数表vtbl的,有this指针,有动态绑定Dynamic Binding。后边还讲到了成员函数。能写多少写多少吧。
- Conversion Function
Operator 类型名(){转换语句}
比如这个例子:
#include<iostream>
using namespace std;
class Fraction
{
public:
Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den) { }
operator double( ) const
{
cout<<"operator double( ) is called!!!"<<endl;
return (double)(m_numerator / m_denominator);
}
private:
int m_numerator; //分子
int m_denominator; //分母
};
int main( )
{
Fraction f(3, 5);
double d = 4+f; //调用operator double( ) 将f 转换为0.6.
return 0;
}
转换函数在函数名前面不能指定函数类型,函数也没有参数,至于是否要加const,根据转换后的结果来判定,一般都会加上const。在使用过程中,不必显示地调用类型转换函数,它往往是自动被调用的,即隐式调用。
23转换构造函数:一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数)。
它有两个作用:一是构造器,二是默认且隐式的类型转换操作符。
- 关键字explicit:
Explicit用于防止隐式转换的,普通的构造函数能过被隐式调用,而explicit构造函数只能被显示调用。
non-explicit-one-argument ctor 可隐式转换单一形参构造函数形如:
#include<iostream>
using namespace std;
class Fraction
{
public:
Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den)
{
cout<<"non-explicit ctor is called!!!"<<endl;
}
Fraction operator + (const Fraction &f)
{
cout<<"operator +(...) is called!!!"<<endl;
return Fraction(this->m_numerator+f.m_numerator, this->m_denominator+f.m_denominator);
}
int getNumerator() const {return m_numerator;}
int getDenominator() const {return m_denominator;}
private:
int m_numerator; //分子
int m_denominator; //分母
};
ostream& operator<<(ostream &os, const Fraction &f)//重载<<运算符
{
return os<<"分子: "<<f.getNumerator()<<"分母: "<<f.getDenominator();
}
int main( )
{
Fraction f(3, 5); //调用non-explicit ctor
Fraction d2 = f+4; //调用non-explicit ctor将4转为 Fraction(4,1)
//然后调用operator +
cout<<d2<<endl; //因为引用传递,所以会再调用一次non-explicit ctor
return 0;
}
- shared_ptr是一种智能指针(smart point),它会记录有多少个shared_ptr共享一个对象。当最后一个指向对象的指针被销毁,这个对象就会被自动删除。
**shared_ptr<int> sp(new int(10)); //一个指向整数的shared_ptr
assert(sp.unique()); //现在shared_ptr是指针的唯一持有者
shared_ptr<int> sp2 = sp; //第二个shared_ptr,拷贝构造函数
assert(sp == sp2 && sp.use_count() == 2); //两个shared_ptr相等,指向同一个对象,引用计数为2
*sp2 = 100; //使用解引用操作符修改被指对象
assert(*sp == 100); //另一个shared_ptr也同时被修改
sp.reset(); //停止shared_ptr的使用
assert(!sp); //sp不再持有任何指针(空指针)
**
网上的例子。
- 迭代器(iterator)
迭代器提供对一个容器中的对象的访问方法,并定义了容器中对象的范围。迭代器就如同一个指针。
- typename
这周课侯老师讲了在泛型编程中typename和class具体有无区别。侯老师也讲了,在模板声明里是完全没用区别的。侯老师也提到了在模板里面的使用是有些微的区别的。但是限于篇幅与时间的限制,侯老师并没有深入讨论,所以在本笔记中,我们会讨论typename与class的区别。
比如我们有一个模板函数,该函数可以打印容器内的所有元素。如下图所示,即使没有typename,函数也能运行。
可是,如果我们写一个自己的容器类,不但有const_iterator这一迭代器类型,还有一个静态变量也叫const_iterator。这时候编译器就会会出现解析错误了。因为我们知道,静变量可以通过使用类名::变量名调用的。所以T::const_iterator不但是一个类型名还是一个变量名,这时候就要加入typename了。
- 范围for语句
C++11新引入了一种更简单的for语句,用于遍历容器或其它序列的所有元素。
语法结构:
for(declaration : expression){
……
}
expression为要遍历的容器
declaration为变量类型,用于存放容器中的元素,若是不清楚容器中的元素类型,可以使用auto类型说明符。
例如:
vector<int> v={0,1,2,3,4,5,6,7,8,9};
for(auto r:v)
{
cout<<r<<endl;
}
在上面的代码中提到了auto,它是类型说明符。
在编程时,常常需要把表达是的值赋值给变量,这就要求在声明变量的时候清楚地知道表达式的类型,然而,往往做不到这一点,所以引入了auto类型说明符,它让编译器通过初始值来推算变量的类型。所以,auto定义的变量一定要有初始值。
6.[GeekBand][C++面向对象高级编程(下)]第四周作业
作业解答在这里