如果想要在一个领域里成为大咖,那么你必须要在这个领域里深耕多年。在C++数百万程序员中,有一位大师,拥有30多年C++开发、研究和教学经验,并亲身参与了C++的演化和变革。业内人士也评价他是世界上最出色的几位C++专家之一,他就是畅销书《C++沉思录》和《C陷阱与缺陷》作者Andrew Koenig。
面对业内不时出现“C++很难学”的声音,Andrew Koenig则认为多向前辈请教能帮助大家精练而快乐地学会C++。
写完Hello world之后该做什么
屏幕上出现Hello world之后,C++程序员的修行之路就此开始。
#include <iostream.h>
int main()
{
cout << "Hello world" << endl;
}
1、向有经验的前辈请教
Andrew Koenig认为,向那些已经学会C++的人请教,这是新手间接获取经验最高效的方法。如果找到一个能回答你的问题并能帮助你解决问题的大神指点,学C++就会容易得多。当然,也不用限制是C++的高手,由于C++源自C,如果遇到C语言的大神程序员,也可以帮助你学习C++。
如何判断谁才是C/C++高手呢?
首先要确认你觉得是专家的人确实知道他们在说什么。所幸的是,有一个简单且通常很有效的办法来辨别:专家就是那种不仅理解你所试图掌握的东西,而且还能给你解释清楚的人。不能清楚地回答你提出的问题的人,并不是你所想的专家。还有人能清楚地解释事情,但却是完全错误的,幸亏这种人很少。
类似的忠告也适用于语言之外的事物,比如许多运行在各种操作系统之上的C++实现。在学习使用某种关于语言和系统的特定组合时,冒出来的问题和系统有关,所以必须有既懂得语言又懂系统的人。记住,任何有用的程序都必须和外部世界交流。
2、找到最适合自己的工具包
能否向当地专家请教的意义比特定编程环境的客观优缺点更重要。但是,最后分析得出,编程环境中最重要的因素还是使用者。一旦使用某种工具到了一定时间,你就会适应这种工具,并能提高使用效率,也就更不愿意换用另一种工具了。
只要你不谎称它是不可逾越的,那么改变使用工具就一点问题也没有了。如果一旦有最新的工具可用就急着用,你就没有时间做别的事情了。如果你靠评价编程工具谋生,这样做当然很好,否则就会掉进一个危险的陷阱。工具是获取结果的手段,如果你只注意手段而忽视了结果,就是在浪费时间。
当然,仅仅因为新事物是新的就拒绝接受也是危险的。最好采用有用的新工具,而不是因为其他的原因。要做到这一点,有一个办法就是要有明显的证据说明新提供的工具值得你费劲去学习如何使用它。如果不能确定,就别为这个工具伤脑筋。我们再一次将理解作为实用性的衡量标准。
3、理解C和C++的共通之处
C++建立在C的基础上。C中的部分思想是任何想有效地使用C++的人必须理解的。如果你已经使用C很长时间并很适应它,这些思想就会成为习惯。如果不是这样,就努力做到这样。
例如,C++程序比起相应的C程序要做更多的声明。理解C程序时,很大一部分精力是花费在阅读组成程序的函数上。而由于C++直接支持数据抽象,所以理解C++程序的工作主要是识别某种标识符的类型,然后阅读该类型的声明。
因此理解声明对C++比对C重要得多。不应该一次又一次地区分指针数组和指向数组的指针之间的区别,以及指向常量的指针和常量指针之间的差别。你应该一劳永逸地掌握。
除了与众不同的声明语法外,C定义了数组和指针之间的一种独特关系。除了C和C++外,没有哪门主流语言用指针操作来定义数组。事实上C的所有程序都运用了这种关系;要彻底学会并理解这一点,而不要每次都从头开始。
由于数组和指针之间的关系,C程序员倾向于用指针运算来表达数组操作。这种与C的++相关的操作会使程序更短小,但需要花一定精力来理解。
void call_each(void (**a)(void), int size)
{
int n = size;
while (--n >= 0) {
void (*p)(void) = *a++;
if (p)
(*p)();
}
}
尽管a从概念上说是个数组,但实际上是一个指针——此时是一个指向“函数指针”的指针。这解释了a的声明中的两个*。看看声明我们就可以很容易地发现这一点,并说:“**a的值是一个函数,可以无参调用,并且没有返回值。”所以a必须是一个指向函数指针的指针。
接下来,注意表达式--n >= 0,如果这个表达式用于这种情况,就是一种将操作重复n次的常用方法。另外,我们可以通过令n=0和n=1来运行该循环,从而证实这一点,同时还可以清楚循环体执行的次数。
然后是关于p的声明——如果你理解a的声明,在这儿就应该没有问题。稍微难懂的是*a++的含义:它取回a所指向的元素,再增加a使之指向序列中的下一个元素。还有,用法if(p)是if(p!=0)的简写形式。
最后,表达式(*p)()是用来决定p指向哪个函数,然后再调用该函数。
这些事情本身并不复杂;它们都是C的一部分,而且被使用了很久。问题在于,如果你开始学习C++,起码要掌握C的这部分知识。好好理解C的这些知识是有好处的,这样你在学习C++时就不用总是停下来去查找关于它们的资料。
4、给自己提问题
如果你只依赖自己完全理解的那部分知识,就必须想办法扩展你的理解范围。增加知识储备的有效方法就是用已知的方法尝试新问题。选择一个你还不理解的C++特性,使用这个特性写个程序,但是注意除此之外,只使用你已掌握的东西。然后做一些其他的工作,帮助你确信程序在做什么,以及为什么。
比如,你不确定自己是否理解复制构造函数和赋值操作符之间的区别,就试着写一个程序,来证明你理解两者的区别。设计这样的程序将会比只看书更加有效。
应该怎样写这样的程序呢?一种方法就是设计一个既用到复制构造函数,又用到赋值操作符的类:
class Test {
public:
Test(const Test&);
Test& operator=(const Test&);
};
然后可以在不同的情况下使用这个类的对象,来观察类是怎样工作的。例如,如果从前面的程序开始,只要输入
Test t;
很快就会发现一个问题。尽管这个类有一个复制构造函数,但它不是缺省构造函数。所以,你至少要给出一个缺省构造函数:
class Test {
public:
Test();
Test(const Test&);
Test& operator=(const Test&);
};
当然,你必须定义赋值操作符和两个已经声明了的构造函数:
Test::Test()
{
cout << "Test default constructor" << endl;
}
Test::Test(const Test&)
{
cout << "Test copy constructor" << endl;
}
Test& Test::operator=(const Test&)
{
cout << "Test assignment operator" << endl;
return *this;
}
这样,通过编写使用这个类的对象和认真地观察结果,你能够学到很多关于构造函数和赋值操作符如何工作的知识。
你的类现在能报告对象的创建、销毁、赋值以及每个对象一个的识别号。例如,考虑下面这个简单的主程序:
int main()
{
Test s;
Test t(s);
s = t;
}
运行时程序打印:
Test 1 default constructor
Test 2 copied from 1
Test 1 assigned from 2
Test 2 destroyed
Test 1 destroyed
如果你能够理解为什么这样输出,就说明你知道了许多关于构造函数、析构函数和赋值操作符的知识。构造这种小巧的类在许多领域都是加强理解的好办法。
如何快速使用C++
Andrew Koenig认为,学习C++最关键的两点就在于:
· 做理解的事情,理解要做的事情。
· 逐步加深扩展理解。
至于其他具体的技巧,Andrew Koenig也提供了一些他认为有用的方法,希望能帮到大家。
做练习时要把握分寸,过犹不及。通过选择一个与你目前的工作相关的问题来学习C++是很有诱惑力的。这是个好主意——只要你不会因为工作太累而忘了学习。
学习新的语言时,你应该在自己熟悉的领域里选择练习课题,这会使你收获更大。如果你做了十几年的窗口组件,那么请尽一切努力让你的练习程序与窗口组件相关。但是,别过分自信,别试图把第一个窗口组件练习做成一个支持窗口组件生成机制的成熟应用程序。如果你又一次从头做起而完全不利用第一次的成果,你肯定会收获更多。
依据操作思考。从C到C++最大的观念性变化就是要停止考虑程序的结构,而开始考虑程序数据的行为。例如,类Test开始仅有一个构造函数和一个析构函数;只有到后来我们知道要它做什么之后,才给它增添数据成员。类所支持的操作——其接口——通常比其结构更重要,因为我们可以容易地改变结构,却很难改变接口。
早些考虑测试。如果你的大部分程序写成了类定义,就应该能确信你的类符合预期。有个好办法就是在写类的代码时也写出测试框架。如果在把程序块连起来之前就对每个块分别进行测试而不是连接后再查找问题,可以省下很多时间。
测试完后别忘了保存测试程序。因为C++中接口和实现是分开的,有可能还要回过头来重新实现你的类,以改善它们的性能。一个好的测试结构可以在日后节省很多时间。
由于以后可以重新实现,所以第一次的实现可以简单些。只做那些你理解并知道如何测试的事情。如果遇到了性能问题,你可以经常重来。如果幸运,你甚至可能发现第一次的实现就够用了。
思考。所有的建议都只是建议。是否对你有用是由你决定的。你可以依照我的建议做任何事情:尽量确切地遵循它,或者拼命反其道而行之,或者忽略它,或者对此嗤之以鼻。不管怎么对待,你都要清楚为什么要这样做。不管你是否理解都要对结果负责。
给C++初学者的书单
C++是C语言的继承,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。
C++擅长面向对象程序设计的同时,还可以进行基于过程的程序设计,因而C++就适应的问题规模而论,大小由之。C++不仅拥有计算机高效运行的实用性特征,同时还致力于提高大规模程序的编程质量与程序设计语言的问题描述能力。
针对初学者来说,学习C++还需要这些入门图书。
斯蒂芬·普拉塔的《C++ Primer Plus》就是C++入门图书中的经典,这本畅销近40年,堪称C++程序员的“引路人”。从第一版出版至今已经升级到了第六版,作者坚持初心——致力于编写一本指导性强、条理清晰而且有用的C语言教程。所以,书中大量完整的、可运行的程序及详细的注释有助于理解代码和概念。
当然,入门图书往往是帮助初学者学会“hello world”,而这之后有更深层次的理解就需要多看一些进阶图书了。
《C++ Primer Plus 中文版第6版》
作者: 【美】Stephen Prata
作者:[美]史蒂芬·普拉达(Stephen,Prata)
京东
内容简介:
史上畅销的重量级C++大百科全书,C++入门的首选图书,累计销量近百万册。
本书分18章,分别介绍了C++程序的运行方式、基本数据类型、复合数据类型、循环和关系表达式、分支语句和逻辑运算符、函数重载和函数模板、内存模型和名称空间、类的设计和使用、多态、虚函数、动态内存分配、继承、代码重用、友元、异常处理技术、string类和标准模板库、输入/输出、C++11新增功能等内容。
本书针对C++初学者,从C语言基础知识开始介绍,然后在此基础上详细阐述C++新增的特性,因此不要求读者有C语言方面的背景知识。
《C++ Primer Plus 中文版第6版习题解答》
作者: [美] 史蒂芬•普拉达(Stephen Prata)
作者:[美],史蒂芬·普拉达(Stephen,Prata)
京东
内容简介:
《C++ Primer Plus(第6版)中文版习题解答》是超级畅销书《C++ Primer Plus(第6版)中文版》的配套习题答案,针对书中的复习题和编程练习,给出了解题思路和答案。
《C++ Primer Plus(第6版)中文版习题解答》共分为18章,每一章的主题与《C++ Primer Plus(第6版)中文版》完全一致。每章开篇采用思维导图的方式列出本章的知识点,然后对每章的重点内容进行了梳理总结,最后则对每章中的复习题和编程练习进行了分析并给出了解答思路,确保读者在彻底夯实理论知识的同时,进一步提升实际编程能力。
作为《C++ Primer Plus(第6版)中文版》的配套参考书,《C++ Primer Plus(第6版)中文版习题解答》特别适合需要系统学习C++语言的初学者阅读,也适合打算巩固C++语言知识或者希望进一步提高编程技术的程序员阅读。
《C++沉思录》
作者: [美]安德鲁·凯尼格(Andrew Koenig) ,芭芭拉·摩尔(Barbara Moo)
作者:[美]凯尼格,[美]莫欧
京东
内容简介:
《C++沉思录》基于作者在知名技术杂志发表的技术文章、世界各地发表的演讲以及斯坦福大学的课程讲义整理、写作而成,融聚了作者10多年C++程序生涯的真知灼见。
《C++沉思录》分为6篇,共32章,分别对C++语言的历史和特点、类和继承、STL与泛型编程、库的设计等几大技术话题进行了详细而深入的讨论,细微之处几乎涵盖了C++所有的设计思想和技术细节。本书通过精心挑选的实例,向读者传达先进的程序设计方法和理念。
《C++沉思录》适合有一定经验的C++程序员阅读学习,可以帮助他们提升技术能力,成为C++程序设计的高手。
《C++ Templates中文版》
作者: 【美】David Vandevoorde 【德】Nicolai M. Josuttis
作者:[美]David Vandevoorde,[德]Nicolai M. Josuttis
京东
内容简介:
本书是C++模板编程的完全指南,旨在通过基本概念、常用技巧和应用实例3方面的有用资料,为读者打下C++模板知识的坚实基础。
全书共22章,以教程的风格介绍了模板的基本概念,阐述了模板的语言细节,介绍了C++模板所支持的基本设计技术,深入探讨了各种使用模板的普通应用程序。附录A和B分别为一处定义原则和重载解析的相关资料。
本书适合C++模板技术的初学者阅读,也可供有一定编程经验的C++程序员参考。
《C++并发编程实战》
作者: 【美】 Anthony Williams (威廉姆斯)
作者:[美]Anthony Williams(威廉姆斯)
京东
内容简介:
本书介绍如何编写或者设计、调试、维护、研究多线程C++程序,并提供了技术模式和工具,可以用来分析并发编程以及降低封装并发交互的复杂性。
书中还提供了大量的实例、练习、可重用的代码以及用于网络通信程序的简化库。