C++学习总结

原创 2012年03月29日 12:42:02

  学习C++有半个多月了,感触比较多。以前一直是和虚拟机类语言(C#/Java)打交道的,尽管早已对C/C++的恶劣环境有所准备,但当开始学习一段时间以后还是不禁吃了一惊。

  本人阅读的是《C++ Primer》,这本书是C++标准委员会许多成员共同著作而成,权威性自然不需多说。书中频繁出现陷阱,注释的小Tip。注释一般是补充解释,提出某些建议或者方案。陷阱的Tip的频繁出现令人惊奇,这大概也是C++被人称作古怪语言的原因。

  废话不多说,上点干货吧:

1.让我想起了Python:

a.字符串分为宽字符串型和普通字符串型。

b.允许在语句中加入\来换行分割显示,编译时会将\忽略掉。


2.让我想起了C:

a.#define #if #ifndef #endif这组预处理。 C用它来做DEBUG开关,以及保护.h头。

b.内置类型的长度是与机器相关的。为了保证兼容性,C/C++一般提倡用.h中用typedef声明了一堆的别名来操作。(例如size_t云云的)。

c.整个世界是全局的,源文件之间通过extern来交流。

d.坚决的将变量分为const和非const两种。const相当于将内存上锁,只许访问不许写入。

e.数组变量在通常情况下解释为int指针变量。然而,更恰当的说法(私以为)是数组变量是一个const指针,它不能改变指向。

int a[2];
a=new int[2]();
这个将产生编译错误。正确的写法应该是:
int a[2];
int *p=a;
p=new int[3]();

f.指针横行。与malloc,alloc,free相对应的。C++给出了delete,new,delete []。操作指针目标对象亦可使用->的便捷方式。


3.让我想起了Java:

a.#include<>:可不就是类似Java的BootstrapClassLoader,直接从jdk的指定lib文件/目录中查找么?

#include "":就是类似Java的AppClassLoader了,从App路径开始找。

b.vector可是Java中大名鼎鼎的Collections之一。C++标准库中的vector似乎与同步性是无关的。接触了C++模板后似乎开始懂得Java泛型中rawType的意思了。

遗憾的是,C++没有C#/Java中的foreach语法。为了操纵Iterator,不得不写一大堆的域操作符。糟糕的是,域操作符不可避免,因为C++模板并不是一个类。

c.对于比int小的整型来说,在计算前会自动提升为int来进行计算。C++中也是如此。


4.让我想起了C#:

a.用using来声明域。using namespace xxx可以在类内直接访问域成员,不需要域操作符::来直接访问。Java/C#/Python访问域均是直接'.'来获得,不知道C++为何如此另类。

b.使用引用。引用便是别名,C#中用ref关键字来指定,C++则用&来指定。

c.const,const <class>*与const *x:在C++中将与指针无关的const理解为#define,将与指针相关的const理解为C#的readonly。

d.操作符重载:也许这真的是个好东西,但是陷阱很多,而且对于新手也并不友好。

e.代理:C++版的delegate便是指针。


5.让我吓一跳的东西

a.C++模板不但可以传入类型,竟然也可以传入具体的值。bitset便是一个例子。

bitset<32> bitvec;

32可不是类型。可千万别把C++模板当做基类。bitset<32>是一个类型,bitset<24>又是一个类型。


b.C++中的对象既可以在栈区创建,也可以在堆区创建。

Person p;
这行语句便是调用默认构造器在栈区创建了一个Person对象。如果想要在堆区动态创建一个Person,则需要这么写:
Person *p=new Person();


c.C++中的数组和指针被称为复合类型。因此声名可是非常讲究的,《C++Primer》中建议对于指针变量从右向左进行阅读。

int *p[4];
int (*p2)[4];

第一个声名的是一个指针数组。(它是数组)

第二个声名的是一个指向数组的指针。(它是指针)


d.C++中的类分为声明和说明。声明一般放在.h文件中,只负责声明。实现体放在.cc文件中,负责对类定义进行实现。

C#/Java中的类定义是这样子的:

class A
{
  public void method(){
//do something
}
}

而C++的类定义却是这样子的:
class A{
public:
 void method();
};

void A::method()
{
//do something
}

e.C++的初始化是非常烦人的东西。它区分初始化情况为内置类型初始化,以及非内置类型初始化。内置变量只有全局变量才会自动初始化,其它情况一概是随机值。为了保证内置变量的正确初始化,必须手动进行初始化赋值或者在新创建时显示调用()来初始化。

C++中的构造器也非常的古怪。C++不像C#/Java一样,初始化的流程并不允许直接的字段初始化。C++只允许在构造器中做声明初始化。


f.C++中的抛异常很非主流。对于Java/C#来说,一般都是抛出一个继承自Exception基类的异常实例。而C++抛异常却是调用函数。

throw run_time_error("abcdefg");


g.C++中有一种称为默认实参的功能。这种功能很强大,但是可能会引起重载混乱。总体来说,这是一个好功能。

int test(int a=12);


h.C++中函数体中的静态变量。

void test()
{
static size_t called=0;
called++;
}

其中的静态变量called在首次调用时会初始化。之后的调用会绕开定义,直接访问变量。本人猜测这是预编译处理的一种语法特性。


6.让我一直警惕的C++特性:

a.预编译:

C/C++相比较虚拟机高级语言来说,多了一个预编译环节。这个环节非常重要,很容易漏掉预编译这部分的思考。区分清楚预编译,能够很大程度上掌握C/C++语法上一些古怪特性的背后原因。比如sizeof,它就是一个预编译阶段的东西。


b.cstring与string:

std内置的String类型与字面量不是一回事情,所有的字面量都是CString。按道理来说,

bool isEmpty(const String& s)
{
  return s.size()==0;
}

isEmpty("abc")

类似这样的代码应该是compile不过去的。因为函数要求传入的是String类型的数据,而实参却是CString。令人奇怪的却是编译没有问题,运行也正常。C++一定是在编译期间背地里做了点手脚。


c.危险的数组:

C#/Java等高级语言,一般会将数组包装成为一个Array对象,其中会包含数组长度的信息。当数组越界时也会迅速报告。而C/C++中,数组就是数组。程序员需要自己维护数组,包括维护数组长度的变量(静态数组)。需要显示的delete [] xx来释放数组资源。


d.危险的类型转换:

C#/Java中类型转换都是安全的,对于C#来说,甚至可以指定implict和explict来添加语法。

C++的内置类型的自动转型是很危险的。数值类型运算前会根据两者类型来做“提升”。糟糕的是,若两者的size一样大,而一个有符号,一个无符号或者一个是浮点数,一个是整数时,转换的预期结果将很不确定。

而对于显示转换来说,C++提供了dynamic_cast,static_cast,const_cast,reinterpret_cast。这些转换很奇怪,reinterpret_cast重新解析了底层位模式结构。也就是说,它只更改类型,但不更改类型的真实内容,仅仅在指针cast中有用,平常是相当危险的东西。const_cast可以将只读的const变量cast成可读写的,非常奇怪的语法。

最后,从一个Java开发人员的角度来说。关于bool类型的自动转换让人感觉不可靠,也很难懂。


e.危险的enum

C++enum的声明与C#没有什么两样。但是事实上,每个enum都对应一个常量类型。并不是所有enum都是int或者long的。enum中的常量数值会根据编译器分析,最终决定一个刚好适配大小的实际类型。

enum Tokens {INLINE=128,VIRTUAL=129}

其中INLINE可能是unsigned char型,VIRTUAL是int型。


f.麻烦的函数重载:

函数重载会经过候选函数->可行函数->最佳匹配这几个步骤。当加入了默认实参时,函数重载变得晦涩难懂。


总结:

有人说《C++ Primer》过于复杂,过于细节,只适合做字典来使用。真正的C++入门教材应该是《Accelerate C++》这样子轻松简单的。

的确,《C++ Primer》不适合初学程序的人阅读。只有对程序设计有了足够深入了解后,才能有所体会。

C++这门语言语法庞杂,陷阱很多。Linus不屑一顾的称C++是门不合格的语言,CSDN的头版也曾有C++是2012年不宜进入的几门技术之一。《JavaScript语言精粹》的作者建议说:每一门语言都有其鸡肋、糟粕、精华的部分。了解全部知识,能够去除鸡肋、糟粕,发扬精华部分,才能成为这门语言的掌握者。

C++继承了C语言的预处理、指针、标准库。添加了模板、类等高层次的封装。重用方面和减少资源消耗方面做了很多努力,这就使得C++变得复杂怪异起来。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

STL编程轻松入门

作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的。STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现。本教程旨在传播和普及STL的基础知识,若能借此机...

C++基础学习总结

C++基础学习总结   0 概述 C++作为一门面向对象的编程语言,以其高效而又实用的特性,既可以进行过程化程序设计,又可进行面向对象的程序设计,是软件开发的直接工具。 1 C++与C的比较 ...

C++学习总结

踏入大学已经半年之久,现在也即将迎来期末考试,心里难免有些起伏、激动。但对于C++却是别有一番滋味在心头,有时看到自己辛苦、努力写出的程序可以顺利的运行,心里是说不出的高兴,可是,有时在电脑前待好长时...

C++学习心得体会

                         &#...

C/C++学习总结(可应对面试题目)

知识结构: 1、if,for,switch,goto 2、#define,const 3、文件拷贝的代码,动态生成内存,复合表达式,strcpy,memcpy,sizeof 4、函数参数传递,...

C++学习笔记——sizeof 用法的详细总结及例程

sizeof 运算符返回一条表达式或一个类型名字所占用的字节数。sizeof运算符满足右结合律,其所得的值是一个 size_t 类型的常量表达式。运算符的运算对象有两种形式: ...

[2015.8.1]C++学习总结

1。Sleep()函数可以暂停程序,括号里面填1000=1秒 注意:Sleep函数的头文件是#include ,而且S要大写 2。内联函数:      //内联函数:提高程序运行效率,但会增加程...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)