打印

【连载】 C++14学习笔记 —— C++编程新时代.

[复制链接]
9435|72
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 dong_abc 于 2013-12-31 20:58 编辑

20131231
一不留神就out了,C++11才刚刚小试牛刀,C++14就来了 。作为虔诚的C/C++派人士,偶会紧跟组织的步伐,时刻保持更新。

虽然已经这么多楼了,不过漏掉的两个重要内容还没补上——右值引用和变长模板。
功力不到家,啃了几次没啃动,要补,补,补......
折腾几个月了,接下来就不是简单的尝试这些知识点了,后面基本应该都是应用了,或许以项目为主题比较好。再看吧......
-----------------------------------------------------------------------------------------------------------------------------------------

20130808
打算深入学一下C++11的新特性。话说C++的重点早已不是面向对象,C++11更是重点突出泛型编程、元编程。

C++不是一种语言,而是一个语言联盟,针对不同的方向,都有不同的应用。

经过10多年的发展,C++11在C++98/03的基础上经过再一次的锤炼,变得更加合理,更加易用,
将再一次推动编程方法的变革。

当然学习难度也更大一些,毕竟内容扩充了,增加了不少新特性以及相应某些特定环境的应用。
甚至提出了一些与传统编程方式迥异的编程方法,这些都是C++经过这些年所沉淀下来的。

程序员应该与时俱进,更新知识库,势在必行!
评分
参与人数 4威望 +19 收起 理由
Ryanhsiung + 6 赞一个!
xlhtracy + 6 很给力!
john_lee + 4 给小草加加油!
refee + 3 赞一个!

相关帖子

沙发
dong_abc|  楼主 | 2013-8-8 20:32 | 只看该作者
本帖最后由 dong_abc 于 2013-8-30 22:02 编辑

第2章  保证稳定性和兼容性

1、C++11关于多态的拓展——final/override控制
1.1  先复习一下多态的基本知识
一个类A中声明的虚函数foo在其派生类B中再次被定义,而且B中的函数foo与A中的函数foo原型一样(函数名、参数列表等一样),
那么我们就称B重载了A中的foo函数。那么此时我们调用B的成员函数就是调用B重载版本。如果同时有A的派生类C,却并没有重载
A的foo函数,那么调用成员函数foo则会调用A中的版本(这段话抄书的,概念我都说不清楚:lol)。

class A 
{
public:   
    virtual void foo() =0;
    ...
};

class B: class A
{
public:   
    void foo() ;
    ...
};

class C: class A
{
public:   
    void foo1() ;
    ...
};

以上A类中声明虚函数foo,  B类重载了A的foo函数,此时B类调用成员函数foo则是调用B重载的版本。
而派生类C未重载基类A的foo函数,此时C类调用成员函数则是调用基类A中的版本。
这就是C++所实现的最简单的多态效应。

1.2  看下面例子
class A 
{
public:   
    virtual void foo() =0;
    ...
};

class B: class A
{
public:   
    void foo() ;
    ...
};

class C: class B
{
public:   
    void foo() ;
    ...
};

从A派生出B,再从B派生出C;B重载了A的foo函数,C重载了B的foo函数。如果B类是我写的,并且因特殊原因,不能让别人(写C类的人)重载,怎么办?
...
...
在B类的foo函数后面加上final即可阻止函数继续重载。
class B: class A
{
public:   
    void foo()  final; //声明为final
    ...
};

class C: class B
{
public:   
    void foo() ;//无法编译通过
    ...
};

1.3  如果工程中的类结构继承较复杂,那么我们怎么知道其成员函数有没有被重载呢?
为了让类的继承关系清晰明了,C++11引入override关键字,在成员函数后面加上override,则此函数一定是被重载过的。
class C: class B
{
public:   
    void foo() override;//此函数重载了基类B中的foo函数。
    ...
};
至此,C++11关于多态的拓展——final/override控制 部分的 内容完 !

使用特权

评论回复
板凳
草民| | 2013-8-8 22:37 | 只看该作者
跟随楼主脚步,关注~

使用特权

评论回复
评论
dong_abc 2013-8-11 11:11 回复TA
草民 
地板
dong_abc|  楼主 | 2013-8-10 21:46 | 只看该作者
本帖最后由 dong_abc 于 2013-8-31 12:20 编辑

2、C++11预定义宏
2.1  _func_ ,在C99中支持_func_ 返回所在函数名的功能。在C++11标准中允许在类/结构体中使用。
class  A 
{
public:
          A():name(_func_) {};
          const char *name ;                        
};

2.2   _Pragma
在之前的标准中,我们都是用一下方式来避免头文件重复编译
#ifndef __NUC1xxRtc_H__
#define __NUC1xxRtc_H__
...
...
#endif

C++11简化了这一点,用_Pragma(“字符串”)即可
_Pragma (“NUC1xxRtc”);

2.3  静态断言
我们之前都是用assert(...)动态断言来处理,这种方法需要程序运行时才能处理,运行程序需要一些额外的开销,
C++11推出了一种静态断言static_assert,在编译时就能提前处理,不需要运行开销。
#include <iostream>
using namespace std;
template <typename T1, typename T2>
auto add(T1 t1, T2 t2) -> decltype(t1 + t2)
{
    static_assert(std::is_integral<T1>::value, "Type T1 must be integral");
    static_assert(std::is_integral<T2>::value, "Type T2 must be integral");
    return t1 + t2;
}

int main()
{
    //std::cout << add(1, 3.14) << std::endl;
    std::cout << add(111, 2) << std::endl;
    return 0;
}

C++11中还更新了一些其他 宏机制,用得较少,就不关注了。

使用特权

评论回复
5
dong_abc|  楼主 | 2013-8-10 22:18 | 只看该作者
本帖最后由 dong_abc 于 2013-8-11 23:59 编辑

本帖的例程编译环境用的QT5.1(内嵌gcc4.8.0),到目前为止,只有gcc4.8.1支持所有C++11新特性,
所以,如果你也想尝试这些新特性,最好用gcc4.8.1命令行来编译。当然嫌命令行麻烦的话也可以用QT5.1或者VS2012,
只是还有少部分新特性不支持。

使用特权

评论回复
6
dong_abc|  楼主 | 2013-8-11 11:56 | 只看该作者
本帖最后由 dong_abc 于 2013-8-30 21:54 编辑

3、异常——noexcept修饰符
在C++98中,一般都是这么运用异常机制 throw(...)  catch() {...}
#include "stdafx.h"
#include<iostream>
using namespace std;
class A{};
int _tmain(int argc, _TCHAR* argv[])
try{
     int j=0;
     char str[]="hello";
     cout<<"please input a exception nember:";
     int a;
     cin>>a;
     switch(a){
                    case 1: throw A();
                    case 2: throw j;
                    case 3: throw str;
                    default:cout<<"no throws here.\n";
                 }
     cout<<"that 's OK .\n";
     return 0;
     }

catch(int){
cout<<"int is exception.\n";
}
catch(char*){
cout<<"char* is exception.\n";
}
catch(A){
cout<<"class A is exception.\n";
}
像以上这种常规的用法效率较低,实际应用的也很少,在C++11中可以使用noexcept来暴力阻止程序继续运行。
有时候简单粗暴的办法反而更靠谱。
class A{} noexcept; //当case1调用A()时阻止程序继续运行
其实noexcept是调用了std::terminate来中断程序的执行。

使用特权

评论回复
7
dong_abc|  楼主 | 2013-8-11 12:43 | 只看该作者
本帖最后由 dong_abc 于 2013-8-30 21:59 编辑

4、关于类成员初始化
4.1  类成员的初始化看起来很简单,其实这里面还是有些要注意的地方,在我还没看《深入理解C++11》
时,都这样初始化类的。
class A 
{
public:   
           foo(const String&) ;
private:
          String name;
};
A::foo(const String& n)
{
   name = n;
}
这里name成员先会被构造函数初始化,然后又被赋值。其实有种显示的初始化语法一步就能完成。
A::foo(const String& n):name(n) {...}

4.2  类成员声明应该与初始化顺序保持一致。
class A 
{
public:   
           foo(const String&) ;
private:
          String name;
          int id;
};
A::foo(const String& n):id(0),name(n)  {...} //运行时出错,id和name声明和初始化顺序应该保持一致。

4.3  类成员若是一个引用,则必须初始化。
class A 
{
public:   
           foo(const String&) ;
private:
          String& name;
          int id;
};
A::foo(const String& n) {...} //编译时出错,name是一个引用,必须初始化

使用特权

评论回复
8
dong_abc|  楼主 | 2013-8-11 13:08 | 只看该作者
本帖最后由 dong_abc 于 2013-8-11 13:09 编辑

今天周末有空,多写点。第一阶段主要是梳理重要的知识点,折腾这些还是为了写程序时求个 简洁、高效、美观以及良好的拓展性。这些通过新生代C++的泛型编程、元编程模式都可以达到。虽然目前还是编程白痴一个,但是我相信只要像现在这样**学习,很快就可以运用泛型编程、元编程。

使用特权

评论回复
9
refee| | 2013-8-11 14:24 | 只看该作者
呵呵 支持楼主 :handshake

使用特权

评论回复
10
dong_abc|  楼主 | 2013-8-11 14:42 | 只看该作者
本帖最后由 dong_abc 于 2013-8-11 14:45 编辑
refee 发表于 2013-8-11 14:24
呵呵 支持楼主






@21小跑堂  

使用特权

评论回复
11
dong_abc|  楼主 | 2013-8-11 20:11 | 只看该作者
本帖最后由 dong_abc 于 2013-8-30 21:57 编辑

5、默认的模板参数与外部模板
5.1  C++11中,模板和函数一样,可以有默认的参数。
template <typename T = int>
class  A {...}; // void A() {...};类模板和函数模板都支持

虽然模板像函数一样支持默认参数,但是有多个模板参数的时候还得遵循“从右往左”的规则。
template <typename T1 = int,typename T2> class A; //编译出错
template <typename T1 ,typename T2 = int> class A; //编译通过
template <typename T1 = int,typename T2 = int> class A; //编译通过
以上都是针对类模板,函数模板参数的位置就没有此限制了。
template <typename T1 = int,typename T2> void A(T1 a,T2 b); //编译通过
SO,类模板参数需要遵循“从右往左”的规则。

5.2  外部模板
我们在test.h中声明一个模板函数

template <typename T > void A(T) {}
在test1.cpp中调用A函数A(1);
在tes21.cpp中调用A函数A(2);
此时编译器实例化出了两个A<int>(int)副本;C++11为了改进这一点,引进了“外部模板”这个概念。

以上实例,我们只要在test1.cpp中做显示实例化
template void A<int>(int);
然后在test2.cpp中声明外部模板,
extern template void A<int>(int);
这样我们在多个文件中调用void A(int)函数编译器就只保留一个A<int>(int)副本。
从这一点可以看出,外部模板 和 外部变量 的使用方式如出一辙 !

使用特权

评论回复
12
dong_abc|  楼主 | 2013-8-11 20:59 | 只看该作者
C++还有巨多给力的地方,限于本人基础较薄弱,目前还使不出C++的威力。

接下来更精彩!

使用特权

评论回复
13
天凉好个秋| | 2013-8-11 21:38 | 只看该作者
关注中

使用特权

评论回复
14
天凉好个秋| | 2013-8-11 21:38 | 只看该作者
今天是11号,看C++11最适合

使用特权

评论回复
15
dong_abc|  楼主 | 2013-8-11 22:09 | 只看该作者
天凉好个秋 发表于 2013-8-11 21:38
关注中


就算没有一个人关注,本帖也会连载到底,第一阶段主要是熟悉C++11强大的新特性阵容,后一阶段就是将这些新的编程方式牵引到单片机/ARM/DSP等处理器上。

使用特权

评论回复
16
aihe| | 2013-8-11 23:19 | 只看该作者
正在学习中,还没看到所说部分,先顶着,回头慢慢品

使用特权

评论回复
17
123de7| | 2013-8-12 11:03 | 只看该作者
也正在学习中  不过  好吧  我承认我是菜鸟

使用特权

评论回复
18
51armfpga| | 2013-8-13 09:03 | 只看该作者
支持楼主,加油!!!!!

使用特权

评论回复
19
jlass| | 2013-8-13 09:17 | 只看该作者
顶一下,虽然看不懂。

使用特权

评论回复
20
dong_abc|  楼主 | 2013-8-13 18:37 | 只看该作者
本帖最后由 dong_abc 于 2013-8-30 22:01 编辑

第3章   通用为本,专用为末

1、关于构造函数 ——继承构造函数/委派构造函数

1.1  继承构造函数。
我们可以将基类的构造函数通过using关键字非常简洁的继承下来为我所用。
struct A {    
void f(int i){}   
void f(int i,double d){}
};

struct B:A{   
using A::f;  //用using来声明基类中的成员函数。   
void f(const char* s){}
};

int main(){
B b;  
b.f(1);
b.f(1,1.1);
//基类的构造被继承下来,都可以被派生类使用。 注意,不仅仅是构造函数  
//可以继承下来使用,普通成员函数也可以的!
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:此id已冬眠...

43

主题

5078

帖子

22

粉丝