一、类型转换

class Fraction

{

public:

explicit Fraction(int num, int den=1)

: m_numerator(num), m_denominator(den)

{ cout << m_numerator << ' ' << m_denominator << endl; }

......

operator double() const {

return (double)m_numerator / m_denominator;

}

......

private:

int m_numerator; //

int m_denominator; //

};

  1. 转出去——利用转换函数(Conversion Function)

    从一个类中转出去的方法是对int(),doube()等"操作符"进行重载。

值得注意的一点是,所有的转换函数都不需要声明返回参数类型,也不需要输入参数。可以通过(double) obj_of_Fraction 进行调用。

除了显式使用转换函数以外,转换函数也会进行隐式调用,例如:

Fraction f(3,5);

double d = 4 + f;

在这种情况下,首先,编译器会检查是否存在+运算符的合适的函数重载。如果没有合适的函数重载被定义,则会先将f隐式转换为double,再进行相加。

  1. 转进来——合理使用explicit关键字避免二义性

    构造函数可以实现"转进来"的目的。Fraction(4)可以创造一个分数,其分母为1,分子为4。

    同样地,"转进来"的构造函数也可以被隐式调用。

    例如对于语句 Fraction d2 = f + 4,第一步,编译器仍然会检查是否存在+运算符的合适的重载Fraction::operator +(double);如果没有合适的函数重载被定义,则会将4转换为分数,然后再进行相加。

    不过,这种隐式转换有时反而是不利的,可能会导致二义性。考虑下面这种情况,如果在类的定义中存在下面的函数:

Fraction operator+(const Fraction& f) {

cout << "operator+(): " << f.m_numerator << ' ' << f.m_denominator << endl;

//... plus

return f;

}

那么,对于d2 = f + 4;有以下两种路径,产生了二义性从而不能通过。

  1. f转double->double 相加->结果转回Fraction->赋值
  2. 4转Fraction->Fraction相加->赋值

为了消除这一二义性,在构造函数前面加了explicit关键字。Explicit关键字的意义是,这个函数只可以被显示调用,而不能被任何形式地隐式调用。 (由于这种声明,Fraction a = 1也不能被调用了。)

如果给拷贝构造函数加explicit关键字,则Fraction B(A) 可以使用,Fraction B = A也不能使用了。

二、pointer-like class

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;

......

}

这里需要特别说明一下对于->操作符重载的调用,考虑如下代码:

shared_ptr<Foo> sp(new Foo);

Foo f(*sp);

sp->method();

将会自动转化为px->method();这里涉及到了'->'的特别行为。'->'运算符的一个特点是,它不会再运算过程中被消耗。'sp->'的运算结果是px,又由于'->'没有被消掉,因此其转换为px->method()。

2)迭代器——一种特别的智能指针

其和智能指针基本一致,只是还需要对++和—运算符进行重载。

T& operator *() const{ return (*node).data; }

T* operator->() const{ return &(operator*();)}

需要注意的一点是,这里显式调用了operator*(),这种形式是非常方便的。

三、Function-like class(仿函数)

即重载()运算符(又名函数调用操作符,其重载时的默认调用位置就在中间),在标准库中被广泛使用。

template <class pair>

struct select1st: public uniary_func<.......>{

const typename pair::first_type&

operator()(const pair &x) const{

return x.first;

}

}

这样就能够像函数一样使用这个类,select1st(pair(1,2));

四、泛型编程初步

泛型编程和面向对象编程是C++的两个重要方面。

  • 类模板和函数模板的作用

    通常来讲,类模板可以被用来做容器、迭代器等;而函数模板则是被用来做泛型算法。

只需要使用template <class/typename T>进行声明。

类模板在使用时需要指明参数类型,但函数模板可以自动进行实参推导。

  • 类的成员模板

    template <class T1, class T2>

    struct pair {

    typedef T1 first_type;

    typedef T2 second_type;

    T1 first;

    T2 second;

    pair() : first(T1()), second(T2()) {}

    pair(const T1& a, const T2& b) : first(a), second(b) {}

    template <class U1, class U2>

    pair(const pair<U1, U2>& p) : first(p.first), second(p.second) {}

    };

    注意其中的成员函数——拷贝构造函数。通过这种成员模板方式,可以实现拷贝构造。

  • 模板的特化

    模板是一种泛化操作,而特化则是一种逆向的操作,其语法是:

    template<>

    struct hash<int>{

    size_t operator() (int x) const {return x;}

    }

通过这种形式,可以给int参数类型单独制定方法,同样的语法也可以使用与函数模板。

cout<<hash<int>()(1000);

其中的hash<int>() 是声明了一个无参临时对象。

  • 模板偏特化

4.1个数上的偏特化

与全特化类似,这种偏特化也是固定参数进行特化。

泛化声明:

template<class T1,class T2>

class vector

{......}

偏特化声明:

template<class T2>

class vector <bool,T2>

{......}

注意偏特化声明中的T2虽然仍写为T2,但与全泛化的T2并没有关系。

4.2范围上的偏特化

这种偏特化是指对于 const * p类型、*p类型、p类型的限制,偏特化就是按照范围划分不同的方法,例如如下的代码:

template <class T>

class C{......}

template <class T>

class C<T*>{......}

当仅有第一种定义时,会自动调用第一种类型的模板;然而当有上两种定义时,对于指针类型的模板参数,可以使用特别的方法定义,这种分类是十分必要的。

  • 模板模板参数

template<typename T,

template <typename T>

class Container

>

class XCls

{

private:

Container<T> c;

public:

XCls()

{

for(long i=0; i< 100; ++i)

c.insert(c.end(), T());

}

};

注意第二个模板参数template <typename T> class SmartPtr ,其本身又是一个模板。

使用方法:

template <class T>

using Lst = list<T, allocator<T>>;

XCls<string, Lst> mylist;

注意:下面的用法不是模板模板参数。

template< class T ,class Sequence = deque<T>>

class stack{

protected:

Sequence C;

}

其中第二个参数制定了stack要依靠什么基本容器类型进行重载,其具有默认值deque。

使用方式为: stack<int,list<int>> s2; 这里的list已经不是模板了,它在具体化之前已经变成了普通的模板参数。

  • 数量不定的模板参数(Since C++ 11,使用包)

    void print(){}

    template< typename T , typename... Types >

    void print(const T& firstArg,const Types &... args){

    cout<<firstArg<<endl;

    print(args...);

    }

…是C++11中的新类型,…代表包(package),也就是以容器存储的数量不定的参数。对于这种数量不定的模板参数,始终采取将参数分为一个和一包的办法,这个包可以作为模板参数,也可以作为函数参数。在print()中,其采用了递归调用方法。也可以将第二参数其作为容器使用。

五、C++的两个常用语法糖

  1. auto类型

    list<string> C;

    auto ite = find(C.begin(),C.end(),target);

    其中的auto类型会自动被推导成 list<string>::iterator

  2. 新的for语法

    for(variable:container){

    ......

    }

变量会在容器中遍历,直到变量结尾。

e.g.

for(auto i:{1,2,3,4}){

......

}

这种语法搭配引用可以修改容器中的值。

for(auto &elem:vector_obj){

elem *= 3;

}

[GeekBand] C++ 高级编程技术 (1)的更多相关文章

  1. [GeekBand]C++高级编程技术(2)

    本篇笔记主要分为两个主要部分,第一部分关于对象模型,第二部分是关于new和delete的更加深入的学习. 一.对象模型 关于vptr(虚指针)和vtbl(虚函数表) 只要用到了虚函数,对象中就会多一个 ...

  2. C#高级编程技术复习一

    从基本的Socket编程进入 (注意:这是转的一篇2011年的文章,有些知识可能该更新了!) 这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Soc ...

  3. Qt高级编程 高清PDF+源|网盘下载地址附提取码|

    书籍作者:Mark Summerfield(马克 . 萨默菲尔德)(英)   书籍译者:闫锋欣内容简介:本书是一本阐述Qt高级编程技术的书籍.本书以工程实践为主旨,是对Qt现有的700多个类和上百万字 ...

  4. 【进阶技术】一篇文章搞掂:Spring高级编程

    本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文基于<Spring5高级编程>一书进行总结和扩展,大家也可以自行研读此书. 十一.任务调度 任务调度主要由三部分组 ...

  5. 读《C#高级编程》第1章问题

    读<C#高级编程>第1章 .Net机构体系笔记 网红的话:爸爸说我将来会是一个牛逼的程序员,因为我有一个梦,虽然脑壳笨但是做事情很能坚持. 本章主要是了解.Net的结构,都是一些概念,并没 ...

  6. MVC高级编程+C#高级编程

    本人今年的目标是学习MVC高级编程和C#高级编程,把自己的基础打的扎实,本文中值是一个开到,定期会在上面记录学习的技术点和心得就,加油吧!!!!!

  7. jquery插件开发继承了jQuery高级编程思路

    要说jQuery 最成功的地方,我认为是它的可扩展性吸引了众多开发者为其开发插件,从而建立起了一个生态系统.这好比大公司们争相做平台一样,得平台者得天下.苹果,微软,谷歌等巨头,都有各自的平台及生态圈 ...

  8. 转载--提高C++性能的编程技术

    读书笔记:提高C++性能的编程技术   第1章 跟踪范例 1.1 关注点 本章引入的实际问题为:定义一个简单的Trace类,将当前函数名输出到日志文件中.Trace对象会带来一定的开销,因此在默认情况 ...

  9. Shell高级编程视频教程-跟着老男孩一步步学习Shell高级编程实战视频教程

    Shell高级编程视频教程-跟着老男孩一步步学习Shell高级编程实战视频教程 教程简介: 本教程共71节,主要介绍了shell的相关知识教程,如shell编程需要的基础知识储备.shell脚本概念介 ...

随机推荐

  1. 记录一次linux线上服务器被黑事件

    1.原因:本来在家正常休息了,我们放在上海托管机房的线上服务器突然蹦了远程不了,服务启动不了,然后让上海机房重启了一次,还是直接挂了,一直到我远程上才行. 2.现象:远程服务器发现出现这类信息 Hi, ...

  2. GCC 编译选项(转)

    转:http://www.cnblogs.com/xmphoenix/archive/2011/03/21/1989944.html gcc提供了大量的警告选项,对代码中可能存在的问题提出警 告,通常 ...

  3. js数组的管理[增,删,改,查]

    今天在设计表单的时候遇到对数组的一些处理的问题,比如说怎么创建一个数组,然后牵扯到数组的增删改查的方法.请看API FF: Firefox, N: Netscape, IE: Internet Exp ...

  4. C#基础--属性 字段

    访问修饰符: private: 私有成员,在类的内部才可以访问 protected: 受保护的成员,该类内部和继承类的内部可以访问 public: 公共成员, 完全公开, 没有访问限制 interna ...

  5. WPF之基于路径的动画

    不是突然想到要做一个路径动画的,是今天谈业务需求的时候偶然谈到的, 一艘船从一个国家到另外一个国家,沿着一条固定的路线前进,就是一个简单的动画效果,以前貌似在书上看到过,所以自己也来做一个. 在网上搜 ...

  6. MVC框架 - AJAX支持

    Ajax是异步JavaScript和XML的一个简写形式.MVC框架包含了不显眼的Ajax内置支持,通过它可以使用辅助方法,在所有的视图添加代码来定义Ajax特性. 在MVC中此特征是基于jQuery ...

  7. ajax步骤和理解

    步骤: 1.利用html+css来实现页面,表达信息: 2.用XMLHttpRequest和web服务器进行数据的异步交换 3.运营js操作DOM,实现动态局部刷新: XMLHttpRequest对象 ...

  8. 【阿里云产品公测】阿里云ECS服务器,PTS网站性能

    作者:阿里云用户321房产网 系统环境:CentOS 6.3 运行组件:Nginx + php + mysql + 缓存加速为eAccelerator 运行网站:基于phpcms开发模板:321房产网 ...

  9. Oracle基础 (十三)日期函数

    日期函数 SYSDATE --当前系统时间 select sysdate from dual; EXTRACT --获取当前年份 select extract(year from sysdate) f ...

  10. 解决ThinkPHP开启APP_DEBUG=>false时报错的问题

    最近用ThinkPHP开发一个项目,本地开发测试完成上传到服务器后,第一次打开正常,再刷新页面时就出现 “页面调试错误,无法找开页面,请重试”的错误,我就郁闷啦,明明本地设置define('APP_D ...