【GeekBand】C++面向对象高级编程-第四周笔记

课堂大纲

1.Conversion Function 转换函数
2.non-explicit-one-argument ctor 可隐式转换单一形参构造函数
3.explicit-one-argument ctor 非隐式转换单一形参构造函数
4.两种特殊的类
4.1. pointer-like class 智能指针
4.2. pointer_like class 迭代器
4.3. function-like classes: functor 仿函数
5.模板
5.1. 类模板
5.2. 函数模板
5.3. 成员模板
5.4. 模板特化
5.5.模板模板参数
6.关于C++标准库
7.reference 引用


注:由于本人对这部分内容的了解不深,所以无法写出很详细的心得,更多的是资料的汇总,引用是从网络上摘取出来的,请见谅。

正文

1.Conversion Function 转换函数

形式如:

#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;
}

运行结果:

捕获.JPG

转换函数的基本规则:
-转换函数只能是成员函数,无返回值,空参数。
-不能定义到void的转换,也不允许转换成数组或者函数类型。
-转换常定义为const形式,原因是它并不改变数据成员的值。
来源

在设计类的时候,如果觉得有必要写转换函数以及认为合理的,都是可以写成转换函数,
用于将该类型转换成其他类型的。
本类型->其他类型

2.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;
}

运行结果:

捕获.JPG

那么如果转换函数和运算符+重载都在同一个类里面呢?按照上述的程序,会发生什么问题?

class Fraction
{
public:
    ...
    Fraction operator + (const Fraction &f)  
    { 
        cout<<"operator +(...) is called!!!"<<endl;
        return Fraction(this->m_numerator+f.m_numerator, this->m_denominator+f.m_denominator);
    }
    operator double( ) const 
    { 
        cout<<"operator double( ) is called!!!"<<endl;
        return (double)(m_numerator / m_denominator); 
    }
    ...
};

编译结果:

捕获.JPG

我个人认为是编译器不知道需要调用内置+运算还是用户自定义的+运算
缘由在于:
1.如果编译器利用类中的double()来将f转换为double型后,便可以用内置+号来作运算;
2.但编译器也可以将4转换成Fraction,然后在调用用户自定义的operator+。
但编译器不知道用户的真实目的是如何,所以便报错了。
有些时候编译器帮助我们完成的隐式转换会带来错误,为了解决这个问题,我们为此引入一个关键字↓

3.explicit-one-argument ctor 非隐式转换单一形参构造函数

class Fraction
{
public:
    explicit 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);
    }
        operator double( ) const 
    { 
        cout<<"operator double( ) is called!!!"<<endl;
        return (double)(m_numerator / m_denominator); 
    }

编译结果是:


捕获.JPG

因为加了explicit关键字后,构造函数不会发生隐式转换,所以double转向Fraction时就会报错。

explicit 只对构造函数起作用,用来抑制隐式转换。
来源

4.两种特殊的类

4.1. pointer-like class 关于智能指针

template<class T>
class shared_ptr
{
public:
    T& operator* ( ) const { return *px; }
    T* operator->( ) const { return px; }

    shared_ptr(T* p) : px(p) { }
private:
    T* px;
    long* pn;
};

使用举例:

struct Foo
{
    ......
    void method(void) {......}
};
shared_ptr<Foo> sp(new Foo);
Foo f(*sp);     //*sp则调用shared_ptr类中的*重载运算符,返回了Foo类的一个指针所指的【对象】;
sp->method( );  //调用shared_ptr类中的->重载运算符,返回了一个Foo的指针。
                //->比较特别,解引用之后还能继续传递下去。

网上摘取一段关于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不再持有任何指针(空指针)
**

[来源](http://blog.csdn.net/sndaxdrs/article/details/6175701)

*注意:assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行*

个人觉得,智能指针实际上就是传统普通指针的扩展,所以究其本质,其内部还是必须有一个普通指针,然后再拓展其功能。

####4.2. pointer_like class 迭代器
示例程序:
```C++
template<class T>
class __list_node
{
public:
    void* prev;
    void* next;
    T data;
};
template<class T, class Ref, class Ptr>
class __list_iterator
{
public:
    ...
    typedef Ptr pointer;
    typedef Ref reference;
    reference operator * ( ) const { return (*node).data; }
    pointer operator -> ( ) const { return &(operator*( )); }
    ...
};
list<Foo>::iterator ite;
...
*ite;          //获得一个Foo object;
ite->method( );//调用Foo::method( );
               //相当于(*ite).method( );
               //相当于(&(*ite))->method( );

迭代器本身就是一种指针,所以当用的时候,实际上是对该迭代器进行解引用,相当于读取它所指的对象的值,所以可以看到重载运算符函数里面是返回data的。
而当调用->的时候,可以分成operator*()被调用后,再被取值,为此相当于是先读取所指对象的值,然后再取地址,所以返回是一个指针。
另外,迭代器和智能指针不同之处是迭代器还要重载++或者--,进行指针移动操作。

4.3. function-like classes: functor 仿函数

被派出差,回来更~

5.模板

5.1. 类模板

5.2. 函数模板

5.3. 成员模板

5.4. 模板特化

5.5.模板模板参数

6.关于C++标准库

7.reference 引用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容