C++主要是C的扩展。最初C++被称为“C with classes”,突出了主要的原始语言扩展。那时已经支持重载函数。从那时起,C++ 获得了异常、分层命名空间、模板形式的通用编程,最后是多线程 支持。从 C++11 开始,还有一些对 garbage collection 的最小核心语言支持,例如使用Boehm garbage collector。较小的扩展包括引用类型、尾随函数返回类型语法、可被覆盖的内存分配和释放机制、运行时类型信息等等。
C 和 C++ 之间的差异,即 C 和 C++ 的“C 子集”之间的差异,总结在 C++11 标准的附录 C 中,标题为“兼容性”,大约 20塞满的页面,其中涉及 C 兼容性的 C1 部分大约有 10 页。
它也是 C++98 和 C++03 中的附录 C,它也是新的 C++14 标准中的附录 C。
该标准的 C++11 附录 C 列出了 C 和 C++ 之间的以下不兼容性:
§C1.1 词汇约定
新关键字(第 2.12 节)
该段落仅引用 C++11 §2.12。以下列表是从该表和 C99 中的相应表生成的。
C99 C++11
_布尔
_复杂的
_假想
对齐
对齐
汇编
自动 自动
布尔
休息休息
案例案例
抓住
字符字符
char16_t
char32_t
班级
常量常量
const_cast
常量表达式
继续 继续
声明类型
默认 默认
删除
渡渡鸟
双双
dynamic_cast
其他的
枚举枚举
明确的
出口
外部外部
错误的
浮动 浮动
为 为
朋友
转到转到
如果如果
内联内联
整数
长长的
可变的
命名空间
新的
无例外
空指针
操作员
私人的
受保护
上市
注册 注册
reinterpret_cast
严格
返回 返回
短短
签字 签字
大小的大小
静态的
静态断言
static_cast
结构体
开关开关
模板
这
线程本地
扔
真的
尝试
类型定义
类型标识
类型名称
工会联盟
未签名 未签名
使用
虚拟的
无效 无效
挥发性的
wchar_t
一会儿一会儿
字符文字的类型从 int 更改为 char (§2.14.3)
字符串文字 const (§2.14.5)
§C1.2 基本概念
C++ 没有“暂定定义”(第 3.1 节)。
struct 是 C++ 中的范围,而不是 C(第 3.3 节)中的范围。
显式声明为 const 且未显式声明 extern 的文件范围的名称具有内部链接,而在 C 中它将具有外部链接 ($3.5)。
main 不能递归调用,也不能获取其地址(第 3.6 节)。
C 允许在多个地方使用“兼容类型”,而 C++ 不允许(第 3.9 节)。
§C1.3 标准转换。
将void* 转换为指向对象的类型需要强制转换(第 4.10 节)。
只有指向非const 和非易失性对象的指针可以隐式转换为void*(第4.10 节)。
§C1.4 表达式。
不允许隐式声明函数(第 5.2.2 节)。
类型必须在声明中声明,而不是在表达式中(第 5.3.3 节、第 5.4 节)。
条件表达式、赋值表达式或逗号表达式的结果可能是左值(§5.16、§5.17、§5.18)。
§C1.5 语句。
现在跳过带有显式或隐式初始化程序的声明是无效的(除非跨整个未输入的块)(§6.4.2,§6.6.4)
现在从声明为返回值但实际上没有返回值的函数(显式或隐式)返回是无效的(第 6.6.3 节)。
§C1.6 声明。
在 C++ 中,static 或 extern 说明符只能应用于对象或函数的名称。在 C++ 中将这些说明符与类型声明一起使用是非法的(第 7.1.1 节)。
C++ typedef 名称必须不同于在同一范围内声明的任何类类型名称
(除非typedef 是具有相同名称的类名的同义词)(第 7.1.3 节)。
const 对象必须在 C++ 中初始化,但可以在 C 中保持未初始化(第 7.1.6 节)。
C++ 中没有隐式 int(第 7.1.6 节)。
关键字 auto 不能用作存储类说明符(第 7.1.6.4 节)。
枚举类型的 C++ 对象只能分配相同枚举类型的值(第 7.2 节)。
在 C++ 中,枚举器的类型是它的枚举(第 7.2 节)。
§C1.7 声明符。
在 C++ 中,使用空参数列表声明的函数不接受任何参数 ($8.3.5)。
在 C++ 中,不能在返回类型或参数类型中定义类型(第 8.3.5 节、第 5.3.3 节)。
在 C++ 中,函数定义的语法不包括“旧式”C 函数(第 8.4 节)。
在 C++ 中,使用字符串初始化字符数组时,字符串中的字符数(包括终止符 '\0')不得超过数组中的元素数(第 8.5.2 节)。
§C1.8 类。
在 C++ 中,类声明将类名引入到声明它的作用域中,并将该名称的任何对象、函数或其他声明隐藏在封闭作用域中(第 9.1 节、第 7.1.3 节)。
在 C++ 中,嵌套类的名称是其封闭类的本地名称(第 9.7 节)。
在 C++ 中,typedef 名称在类定义中使用后可能不会在该定义中重新声明(第 9.9 节)。
§C1.9 特殊成员函数。
隐式声明的复制构造函数和隐式声明的复制赋值运算符不能复制 volatile 左值(第 12.8 节)。
§C1.10 预处理指令。
__STDC__ 是否已定义,如果已定义,其值是什么,由实现定义(第 16.8 节)。
为了简化比较关键字表的重新生成,并建立对给定表的信心,以下是用于生成它的 C++ 程序:
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
#define ITEMS_OF( c ) c.begin(), c.end()
enum class Language { c, cpp };
auto compare( Language const a, Language const b )
-> int
{ return int( a ) - int( b ); }
struct Keyword
{
string word;
Language language;
friend
auto operator<( Keyword const& a, Keyword const& b )
-> bool
{
if( int const r = a.word.compare( b.word ) ) { return (r < 0); }
return (compare( a.language, b.language ) < 0);
}
};
void add_words_from(
string const& filename, Language const language, vector< Keyword >& words
)
{
ifstream f( filename );
string word;
while( getline( f, word ) )
{
words.push_back( Keyword{word, language} );
}
}
auto main() -> int
{
vector< Keyword > words;
add_words_from( "kwc.txt", Language::c, words );
add_words_from( "kwcpp.txt", Language::cpp, words );
sort( ITEMS_OF( words ) );
int const w = 20;
int previous_column = -1;
string previous_word = "";
cout << left;
for( Keyword const& kw : words )
{
int const column = (int) kw.language;
int const column_advance = column - (previous_column + 1);
if( column_advance < 0 || previous_word != kw.word )
{
cout << endl;
if( column > 0 ) { cout << setw( w*column ) << ""; }
}
else
{
cout << setw( w*column_advance ) << "";
}
cout << setw( w ) << kw.word;
previous_column = column; previous_word = kw.word;
}
cout << endl;
}