隨著報考人數增多,很多學員錯過班期
因此建議先預定全年名額,拿到試題、教材。
然后根據工作時間選擇合適班期
參加現場培訓、考試。
9?月份
上海 9-11號培訓 12號考試
深圳16-18號培訓19號考試
北京23-25號培訓26號考試
10?月份
廣州14-16號培訓17號考試
無錫21-23號培訓24號考試
濟南21-23號培訓24號考試
杭州21-23號培訓24號考試
成都28-30號培訓31號考試
11?月份
北京11-14號培訓15號考試
上海18-20號培訓21號考試
深圳25-27號培訓28號考試
12?月份
廣州 9-11號培訓12號考試
杭州16-18號培訓19號考試
成都23-25號培訓26號考試
濟南23-25號培訓26號考試
本文主要參考了C++標準委員會出品的 Mix-c-and-cpp 和 Learning C++ if you already know C 兩個鏈接對應的一些問答內容,加上我個人的理解完成。本文先會說明C++和C的發展歷史和它們之間關系,然后從編程范式上提綱挈領地總結一下表達下我個人的感受,之后從幾個區別點來具體說明它們的不同。有不準確或疏漏的地方還請大家指正,謝謝。
然后,關于C++語言標準參考文檔我推薦 cppreference c++ language document ;關于C語言標準參考文檔我推薦 cppreference c language document ;有興趣的朋友可以看看,當然也可以把它們當成參考文檔查閱用。
然后現在最新的C++標準是C++1x,C標準是C1x,希望大家都可以用最新的標準,因為最新的標準填上了很多坑。另外,提醒一下,其實C++包括兩個部分:C++語言(language)部分和C++庫(library)部分,學C++這兩部分都要學好;學習C語言也是一樣。
本文的主要內容包括四個部分。第一部分是 背景:C1x與C++1x是一對兄弟,C95是他們的爹 ,第二部分是 C/C++區別-從編程范式上來講 ,第三部分是 C/C++區別-重要的(區別0-9) , 第四部分是 C/C++區別-其他(區別10-12和其他) 。本文最末給出了一些相關的參考文章。
(一/四) 背景:C1x與C++1x是一對兄弟,C95是他們的爹
引用一下 Learning C++ if you already know C 中的一段話,概括一下C++1x/C1x和C95的關系。C++98和C99其實已經有不兼容的地方了,那么在之后的進程中這些不兼容的點會更多;因為事實上在語言層面上,C++新標準和C新標準制定的是不同語言的標準,只不過它們的語法有許多相同或者相似的部分。然后下面引用的段落中的幾個鏈接為C++之父推薦看的文檔或書籍,大家感興趣的話,可以看一看這些資料。
C++ is a direct descendant of C95 (C90 plus an Amendment) that retains almost all of C95 as a subset. C++ provides stronger type checking than C and directly supports a wider range of programming styles than C. C++ is “a better C” in the sense that it supports the styles of programming done using C with better type checking and more notational support (without loss of efficiency). In the same sense, ANSI C90/C95 is a better C than K&R C. In addition, C++ supports data abstraction, object-oriented programming, and generic programming (see The C++ Programming Language; Appendix B discussing compatibility issues is available for downloading).
We have never seen a program that could be expressed better in C95 than in C++ (and we don’t think such a program could exist – every construct in C95 has an obvious C++ equivalent). However, there still exist a few environments where the support for C++ is so weak that there is an advantage to using C instead. There aren’t all that many of those left, though; see Stroustrup’s (incomplete) compilers list.
For a discussion of the design of C++ including a discussion of its relationship with C see The Design and Evolution of C++.
Please note that “C” in the paragraphs above refers to Classic C and C95 (C90 with an Amendment). C++ is not a descendant of C99; rather, both are derived from C95. C++11 adopted all of C99’s preprocessor extensions and library extensions, but not C99’s new language features, so language features like the restrict keyword that were added in C99 are generally not part of ISO C++. Here is a description of the differences between C++98 and C99.
(二/四) C/C++區別-從編程范式上來講
從編程范式上來講,C語言是一種遵循面向過程,或者俗稱(imperative programming/procedure programming)編程范式的程序設計語言,其關注點在于對解決問題的Solver的抽象,所以C語言更接近于匯編。
而C++與其設計理念不同,C++試圖允許大家使用各種編程范式:
比如首先支持使用C語言中的面向過程的編程范式。
比如支持面向對象的編程范式,使得我們可以開始抽象問題本身,通過定義抽象數據類型(Abstract Data Type)來抽象問題,封裝問題對應的數據在類作用域內。然后我們可以合理地而不是濫用面向對象設計思想的封裝/繼承/ 多態來使得我們寫的代碼更容易維護。
比如模板的引入,使得我們可以進行泛型編程;通過定義函數模板來利用函數參數列表的類型推導生成模板函數,通過定義類模板結合比如偏特化的技術來生成模板類,函數模板和類模板都是編譯器看的東西,具體的代碼中,只有我們產生的具體模板函數和模板類會占代碼段的空間。當然模板的引入還讓許多人可以進行模板元編程,讓那些可以在編譯時候計算的東西放在編譯時進行,有人還證明了模板元編程是圖靈完備的。
比如lambda表達式的引入,讓我們進行函數式編程更加自然,從語言層面而不是庫函數的層面來支持我們函數式編程。庫層面的話只能使用函數指針/或者C++的函數對象,來進行函數式編程,并且函數一定會綁定有一個名字。有興趣的朋友可以學一學MIT Structure and Interpretation of Computer Programs。
當然還有其他的內容,這里我僅僅根據我個人的理解,在這里拋磚引玉。感興趣的朋友可以搜集資料查看,如果有重要內容補充的話,請進行評論。
(三/四) C/C++區別-重要的
區別0,函數重載:C語言不支持 函數重載 ,其函數簽名不包含參數列表。
因而在C語言中,也就不能夠像C++那樣 運算符重載 了。下面通過兩個小代碼來說明函數重載的區別,在c語言中我不得不取不同的函數名字來表達相近的操作加的意思。
區別0,C代碼:non_overload.c
#include "stdio.h" #include "stdlib.h" #include "string.h" int add_int(int lhs, int rhs) { return lhs + rhs; } void add_str(const char *lhs, int lhs_size, const char *rhs, int rhs_size, char *res, int *res_size) { memcpy(res, lhs, lhs_size); memcpy(res + lhs_size, rhs, rhs_size); res[lhs_size + rhs_size] = '\0'; *res_size = lhs_size + rhs_size; } int main() { printf("%d + %d = %d\n", 1, 2, add_int(1, 2)); const char *lhs = "abcd"; const char *rhs = "efgh"; char *res = malloc(sizeof(char) * 20); int res_size = 0; add_str(lhs, 4, rhs, 4, res, &res_size); printf("%s + %s = %s, size:%d\n", lhs, rhs, res, res_size); free(res); return 0; }
區別0,C++代碼:with_overload.cpp
#include 區別1,函數參數傳遞:在C語言中不從語言層面支持傳引用,需要通過指針類型的值傳遞實現傳引用的功能。 詳細的Demo代碼如下,可以看到語法層面上的引用傳遞支持讓代碼看起來更舒服: 區別1,C代碼:only_value_passing.c #include "stdio.h"
void increment(int *int_ptr) {
printf("Before: %d\n", *int_ptr);
*int_ptr += 1;
}
int main() {
int integer = 0;
increment(&integer);
printf("After: %d\n", integer);
}
區別1,C++代碼:ref_passing.cpp #include 區別2,函數的聲明(Declaration)和使用:在C語言中使用某個在其其他編譯單元的函數可以不先聲明(當然這是一個不好的編碼習慣,在實際開發中要極力避免),而在C++中這是不合法的。 下面通過代碼來說明這一點,然后希望大家在使用的時候可以遵循好的編碼規范: 區別2,C代碼:function_declaration.c #include 區別2,C++代碼:function_declaration.cpp #include 區別3,模板:模板在我的理解中,是生成代碼的工具,但比C中的宏更安全更強大。 比如函數模板是生成模板函數的工具,本身不會占有代碼段空間,而生成的模板函數則會占有代碼段空間,這一點是相當有用的,我可不愿意讓我的代碼中有很多不會被調用的死代碼(dead codes)。C語言不支持 模板 ,因而不能輕松愉快地進行所謂的泛型編程/模板元編程,只能用容易出錯,難以讀懂的宏定義和預處理元編程。 在C++中模板主要有以下幾種:函數(function)模板,類(class)模板,變量(variable)模板(一種語法糖,讓我們不用繁瑣地寫類模板),別名(alias)模板,具體可以參考 Cppcon2016 對應的Youtube上發布的有關 Template Normal Programming Part1 和 Template Normal Programming Part2 的視頻。這個作者用通俗易懂的例子給我們講述了模板在Modern Cpp中的使用,我個人強力推薦大家進行觀看,不過大陸的朋友觀看Youtube需要翻墻。 下面貼一個知乎的一個高贊同的回答鏈接 C++ 模板元編程的應用有哪些,意義是什么 ,作者說主要應用有:編譯時計算,補充類型系統,Domain Specific Language(是你說的“開發新語言”么?)。不過我個人不推薦大量地使用模板元編程,畢竟代碼是寫給人看的,而且有其他語言,可以幫助我們用更好的方式做這些事情。我個人對語言又是沒有歧視的,哈哈。 我下面用代碼展示下一個函數模板,說明一下C++模板的泛型設計,比C語言使用宏定義進行預處理元編程要更可讀可寫,并且不太容易出錯。 區別3,C語言代碼:pre_processing.h ElemType FuncName(ElemType lhs, ElemType rhs) { return lhs + rhs; }
區別3,C語言代碼:pre_processing.c #include "stdio.h"
int main() {
//自己做編譯器做的事情。。。
#undef ElemType
#undef FuncName
#define FuncName add_int
#define ElemType int
#include "pre_processing.h"
printf("1 + 2 = %d\n", add_int(1, 2));
#undef ElemType
#undef FuncName
#define FuncName add_double
#define ElemType double
#include "pre_processing.h"
printf("1 + 2 = %.2lf\n", add_double(1.0, 2));
}
區別3,C++代碼,function_template.cpp #include 區別4,struct/class/enum/enum class, 在講述之前,我先提醒一下大家在C++中, struct 和 class 對編譯器看來,只有默認的成員變量作用域不同,一個是public,另一個是private,然后其他沒有區別;推薦一個知乎不錯的回答 c++為什么要讓struct可以定義成員函數?,我引用一下里面的一些精華內容,從3點概括C++編譯器可以做的“魔鬼操作”: 1、對普通成員函數,為它自動添加this參數,并在調用它時,自動把 obj.method() 轉換成 method(obj)格式;并識別出函數中涉及的、沒有顯式使用this的成員變量、為它加上this。除此之外,別的什么都不用做。2、對虛函數,需要為繼承鏈上的每個類產生一個全局結構體,在這個結構體里按次序安排指向該類所有虛函數的指針,這就是虛函數表;然后在類里添加一個指向屬于自己的虛函數表的指針。那么,當用戶調用某個對象的第N個虛函數時,到虛函數表查找并獲取第N個函數指針指向的內容;然后類似調用普通成員函數一樣,把 obj.method() 轉換成 method(obj)格式,多態就實現了。3、 當然,除此之外,還要在編譯時執行權限檢查,避免非法訪問類的protect/private成員(struct默認權限是public,class是private);以及另外一些瑣碎工作。 好了,有了這些預備知識之后,我再提醒一下大家,在C語言的struct中,我們是不可以定義方法的,我個人對這個的看法是,C語言的設計者應該認為struct,union和指定內存alignment的一些設計已經足夠抽象出數據了,你要寫一個solver就自己去寫方法,如果你想要搞個函數對象也可以,把函數指針放到結構體里面去就好了。我覺得這很符合C遵循的面向過程(imperative programming/procedure programming)的編程范式,和從充斥面向對象的cfront發展而來的C++相比有很大不同。 然后值得注意的是,在C語言中,我們使用strut和enum定義出來的類型的時候,我們要加上struct;如果C++中是 UserType var; ,那么在C中就是 struct UserType var;。然后C++11引入了 enum class 讓我們的枚舉類型更類型安全,詳細可以參考 C++11 FAQ中enum class的內容 和 一個不錯的講enum class的博客 ,我就不寫代碼展示這些概念了,大家可以查看這兩個鏈接的內容學習。 區別5,面向對象:C語言不支持面向對象,不包含面向對象中的對象語義學。 比如申請空間(可以是進程棧空間或是通過malloc出來的進程堆空間)后進行構造,然后在退出作用域的時候進行析構。因而,我們不能運用所謂的 RAII(Resource Acquisition Is Initialization)機制 ,來管理資源(資源可以是堆空間,也可以是文件/網絡連接之類)。在C語言中,我們也不能使用封裝/繼承/和基于虛表(virtual-table)的多態等面向對象特性,只能自己代替C++編譯器,通過函數指針實現多態。 下面我用一個給大家展示一下C++的RAII機制: #include 運行結果: Acquire Resource, e.g, heap memory allocation/file handle operation/other resources
Release Resource, e.g, heap memory allocation/file handle operation/other resources
下面我用簡短的代碼展示一下C++面向對象的多態,和C語言比較裸的函數指針(也就是面向對象多態實現的基礎)的多態: #include "stdio.h"
#include "stdlib.h"
struct Polygon {
int width_, height_;
void (*area_ptr_)(struct Polygon *ptr_ploy);
};
struct Polygon *PolygonConstructor(int width, int height) {
struct Polygon *ppoly = malloc(sizeof(struct Polygon));
ppoly->width_ = width, ppoly->height_ = height;
return ppoly;
}
void area_rectangle(struct Polygon *ptr_ploy) {
printf("Rectangle Width:%d,Height:%d\n", ptr_ploy->width_, ptr_ploy->height_);
printf("Rectangle Area:%d\n", ptr_ploy->width_ * ptr_ploy->height_);
}
struct Polygon *RectangleConstructor(int width, int height) {
struct Polygon *ppoly = PolygonConstructor(width, height);
ppoly->area_ptr_ = area_rectangle;
return ppoly;
}
void area_triangle(struct Polygon *ptr_ploy) {
printf("Rectangle Width:%d,Height:%d\n", ptr_ploy->width_, ptr_ploy->height_);
printf("Rectangle Area:%d\n", ptr_ploy->width_ * ptr_ploy->height_ / 2);
}
struct Polygon *TriangleConstructor(int width, int height) {
struct Polygon *ppoly = PolygonConstructor(width, height);
ppoly->area_ptr_ = area_triangle;
return ppoly;
}
int main() {
struct Polygon *ppoly_rec = RectangleConstructor(4, 5);
ppoly_rec->area_ptr_(ppoly_rec);
free(ppoly_rec);
printf("\n");
struct Polygon *ppoly_tri = TriangleConstructor(4, 5);
ppoly_tri->area_ptr_(ppoly_tri);
free(ppoly_tri);
}
運行結果: Rectangle Width:4,Height:5
Rectangle Area:20
Rectangle Width:4,Height:5
Rectangle Area:10
區別5,多態,C++代碼:polymorphism_demo.cpp //參考:http://www.cplusplus.com/doc/tutorial/polymorphism/
#include 運行結果: Polygon Constructing...
Rectangle Constructing...
Rectangle Width:4,Height5
Rectangle Area:20
Rectangle Destructing...
Polygon Destructing...
Polygon Constructing...
Triangle Width:4,Height5
Triangle Area:10
Triangle Destructing...
Polygon Destructing...
區別6,類型安全:C語言一些操作在C++中被認為是非類型安全的,比如(void *)類型的數據使用。void * 是一種特殊的泛型指針(generic pointer),詳細可以看看 FAQ > Casting malloc 里面介紹的內容。 下面的這句代碼在C中可以編譯: int *x = malloc(sizeof(int) * 10);
而在C++中則需要進行強制類型轉換才可以: int *x = (int*) malloc(sizeof(int) * 10);
區別7,內存管理:C語言沒有 operator new/ operator delete 和 operator new[]/operator delete[],在全局作用域下也沒有用戶無法修改的函數 placement new 和 placement delete;在C語言中只有 malloc 和 free 這兩個全局作用域的函數。 區別7,我就不用代碼展示了,我給大家個鏈接,上面有代碼,C vs C++ - By Alex Allain 。 區別8,Technical Specification提案(library上和language上):C++有更多的語言層面和庫層面的提案。比如在C++標準委員會搞的這個 IsoCpp-Current Status 上,我們就可以看到C++新標準將考慮支持的一些庫層面和語言層面重要的提案,列舉幾個我比較關注的:Parallelism, Concurrency, Transactional Memory,File System, Networking,Concepts, Modules。這個內容比較復雜,感興趣的朋友可以查閱鏈接看看。 (四/四) C/C++區別-其他 區別9,命名空間:C語言沒有namespace的說法,所以很可能產生命名困難,因為變量都是global的作用域。 區別10,關鍵詞(語言特性):C++引入了一些關鍵字是C語言中沒有的,比如說class, template, bool,C語言也有關鍵字是C++中沒有的,比如說restrict。 區別11,庫:C++有更大的庫,比如說數學相關的庫;比如說C++11引入的多線程有關的庫#include 區別12,主函數返回值:C語言主函數必須加上 return 0; ,而C++的編譯器會自動給主函數加上 return 0;。 區別...,還有很多其他區別: 比如:異常機制,I/O處理庫等等,在這里我就不一一列舉了。 如有侵權,請聯系刪除!
區別5,Raii Demo C++代碼:raii_demo.cpp
區別5,多態,C代碼:polymorphism_demo.c