C++听课笔记之一(候捷主讲)


01_导读

本课程目标:

1、泛型编程(Generic Programming)和面向对象(Object-Oriented Programming)虽然分属不同的思维,但它们正是C++技术主流。因此,本课程也探讨template(模板)。

2、深入探讨面向对象之继承关系所形成的对象模型(Object Model),包括隐藏域底层的this指针、vptr(虚指针)、vtbl(虚表),virtual mechanism(虚机制)以及虚函数(vitual function)造成的polymorphism(多态)效果。


02_转换函数(conversion function)

//demo2_1
class Fraction
{
public:
    Fraction(int num,int den=1)
        :m_numberator(num),m_denominator(den){}
    oprator double() const
    {
        return (double)(m_numberator / m_denominator )
    }
private:
    int m_numberator;
    int m_denominator;
}

//...
Fraction f(3,5);
double d=4+f;//调用operator double() 将f转换为0.4 

  转换函数分为两类,一类是转出去(把 class对象转为其它),另一类是转进来(把其它转为class对象)。编译器在编译程序最后一行时,首先寻找有没有operator+ 的符号重定义,如果有,并且允许一个整型加一个类对象返回一个double型,则采取此方案。如果上述方案不成立,那么编译器将在类对象f中寻找转换函数,看时候能将f转换为double类型。本次便是采取了这个方案。

注意:

(1)转换函数一定不带参数。

(2)转换函数没有转换类型,而其返回类型就是double型。

(3)转换函数通常要加上const。该加最好加上,否则后续编程可能会带来隐患。

(4)转换函数的意义就是当使用。

(5)任何一个class,只要程序员认为合理都可以定义转换函数,并且可以书写多个转换函数。


03_non-explicit one argument constructor

//demo3_1
class Fraction
{
public:
    Fraction(int num,int den=1)
        :m_numberator(num),m_denominator(den){}
    Fraction operator+ (const Fraction &f)
    {
        return Fraction(......);
    }
private:
    int m_numberator;
    int m_denominator;
}

//...
Fraction f(3,5);
double d2=f+4;//调用non-explicit ctor 将4转为Fraction
              //然后调用operator+

one argument是一个术语,说的是只要一个实参就可以了。这种类的设计师合理的,因为例如数字5,它其实是5/1,因此传递参数只传递一个5过去就可以了。但是如果需要传递两个参数的话,它也能够接收。

这个例子中是将数字4(字面值为int类型)编译器通过调用构造函数将其转换为了Fraction类型。具体分析:当编译到最后一行时,编译器使用+号重载,首先f是Fraction对象,然后调用Fraction类的+号重载函数进行加右边的数据,但是右边是一个整型,按照加号重载的定义,右边应该加一个Fraction类型的数据,因此编译器试图将4通过调用构造函数转换为Fraction类型,这是合理的,因为4可以理解为4/1。因此实现了二者的相加。

在上个例子是把class对象转换成了double类型的数据(转出去),而这个例子是把int型的数据转换成了class对象(转进来)。但是我们口语中所说的转换函数其实指的并不是这一种,而是上个例子。即转出去。

//demo3_2
class Fraction
{
public:
    Fraction(int num,int den=1)
        :m_numberator(num),m_denominator(den){}
    operator double() const
    {
        return (double)(m_numberator / m_denominator )
    }
    Fraction operator+ (const Fraction &f)
    {
        return Fraction(......);
    }
private:
    int m_numberator;
    int m_denominator;
}

//...
Fraction f(3,5);
double d2=f+4;//ERROR ambiguous

转出去和转进来都行得通,而编译器就会引起歧义。因此报错。

//demo3_3
class Fraction
{
public:
    explicit Fraction(int num,int den=1)
        :m_numberator(num),m_denominator(den){}
    operator double() const
    {
        return (double)(m_numberator / m_denominator )
    }
    Fraction operator+ (const Fraction &f)
    {
        return Fraction(......);
    }
private:
    int m_numberator;
    int m_denominator;
}

//...
Fraction f(3,5);
double d2=f+4;//[ERROR]conversion from 'double' to 'Fraction ' requested

explicit关键字用90%会用在构造函数前面。它的意思是不允许将4这样的int类型转换为Fraction,也就是不允许编译器那么的自动。如果没有添加这个关键字,则编译器默认为non-explicit。


04_pointer-like classes

这个class实例化出来的对象像指针,但是它比普通的指针更聪明,我们称之为智能指针。指针允许的用到的地方,这个对象都可以应用。指针允许的操作它都允许。c++2.0有好几个智能指针,但是他们都拥有如图示的指针结构。即在封装的内部有一个真正的指针(天然的指针),然后被封装成一个类,代表一个智能指针。

1、下述代码是pointer-like的第一大分类(智能指针):

//demo4_1
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->method();//等价于px->method();

在这里,一定会有5678行的四句代码。这是指针最基本的功能。

2、pointer-like的第二种用法:迭代器

//demo4_2
template<class T,class Ref ,class Ptr>
struct __list_iterator
{
    typedef __list_iterator<T,Ref,Ptr>self;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __list_node<T>* link_type;
    link_type node;
    bool operator ==(const self& x)const{    return node == x.node;    }
    bool operator !=(const self& x)const{    return node != x.node;    }
    reference operator*()const {    return (*node).data;    }
    pointer operator->() const {    return &(operator*());    }
    self& operator++(){    node = (link_type)((*node).next);return *this;}
    self operator++(int) {self tmp = *this; ++*this; return tmp;}
    self& operator--(){node = (link_type)((*node).prev);return *this;}
    self operator--(int) {self tmp = *this; --*this;return tmp;}
};
template <class T>
struct __list_node
{
    void *prev;
    void *next;
    T data;
}

迭代器也可以算作一个智能指针,但是它与普通智能指针有所不同。

//demo4_3 
//应用示例  
    reference operator*()const {    return (*node).data;    }
    pointer operator->() const {    return &(operator*());    }

list<Foo>::itrator ite;
...
*ite;//获得一个Foo Object
ite->method();
//意思是调用Foo::method()
//相当于(&(*ite))->method();

要理解->和*为什么设计成这样。


05_function-like classes

设计一个类,使之像一个指针,或一个函数。函数必然有个函数名称,然后有个小括号作用上去,而其实上小括号的名称叫做function call operator  (函数调用操作符)。下述代码便是库中function-like的一个例子。它的类属性对小括号进行重载,使它实例化的对象能够接受小括号传递的参数,这就类似于函数。一个class中如果试图重载(),我们就称其为function-like。标准库中有许多仿函数。其中的仿函数都继承一些奇特的基类(base class)。

template<class T>
struct identity
{
    const T & operator()(const T &x)const{return x;}
};
template<class Pair>
struct select1st
{
    const typename Pair::first_type&
    operator()(const Pair &x) const
    {    return x.first    }
}
template<class Pair>
struct select2nd
{
    const typename Pair::second_type&
    operator()(const Pair &x) const
    {    return x.second    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值