分享

C 之C 与C的区别一

 拾叁亿人 2023-04-05 发布于云南

C++与C区别概述

C++ 是在 C 语言的基础上发展而来的一门编程语言,它在语法、数据类型、函数、运算符等方面都比 C 语言更为丰富和灵活,同时也具有更好的支持面向对象编程(OOP)的能力,因此被广泛应用于各种系统和应用程序的开发中。以下是 C++ 与 C 语言的一些主要区别:

  • 支持面向对象编程:C++ 支持面向对象编程的特性,例如封装、继承、多态等,而 C 语言并不支持。
  • 操作符重载:C++ 允许用户对运算符进行重载,即可以自定义运算符的含义和操作对象,而在 C 语言中则不支持此功能。
  • 异常处理:C++ 支持异常处理机制,可以捕获和处理程序运行时遇到的异常,而 C 语言则需要通过错误码等方式进行错误处理。
  • 标准库:C++ 标准库中包含了大量的库函数和容器,例如 string、vector、map 等,而 C 语言的标准库则比较简单,只包含了常用的库函数。
  • 命名空间:C++ 中支持命名空间的概念,可以帮助避免命名冲突的问题,而 C 语言中则不支持。
  • 自动类型推断:C++11 引入了自动类型推断关键字 auto 和 decltype,可以根据赋值语句的类型推断出变量的类型,而在 C 语言中则需要手动声明变量类型。

以上只是 C 和 C++ 之间的一些简单区别,实际上它们在很多方面有着类似的语法和特性。对于学习者来说,如果已经掌握了 C 语言,那么学习 C++ 就会比较容易,因为 C++ 的语法和特性可以看作是 C 语言的扩展和补充。接下来我们详细了解一些基础阶段必须要掌握的C++与C的区别。

C++与C的区别详解

文件区别

C 和 C++ 的文件有以下几点不同:

  • 头文件扩展名不同:C 的头文件扩展名是 .h,而 C++ 的头文件扩展名是 .h 或 .hpp。
  • 标准 I/O 库的不同:C 使用的标准 I/O 库是 stdio.h,而 C++ 使用的是 iostreamC++标准库中所有头文件都是无h后缀包含:#include <iostream>
  • C++中包含C语言的头文件有以下两种方案直接包含:#include <stdio.h>无h后缀包含:#include <cstdio>

命名空间

在 C++ 中,命名空间是用于防止命名冲突的重要机制,可以将全局作用域分为若干个小的作用域,不同的空间可以分别存放变量、函数等名称相同但含义不同的实体。C++ 中的命名空间是一个重要的语言特性,可以防止不同作用域内同名实体的冲突。对于大型程序的开发来说,合理使用命名空间可以提高代码的可读性和可维护性。命名空间主要是掌握以下内容

  • 如何创建正常包含方式创还能先声明后实现的写法
  • 如何访问数据运算符: 作用域分辨符 ::空间名::成员省略前缀的方式:using namespace 空间名;
  • 命名空间嵌套问题:剥洋葱即可
  • 命名空间作用提高标识符的使用率避免命名污染

命名空间| 创建

命名空间创建语法如下:

文章图片1

如下测试代码:

#include <iostream>//直接实现namespace MM{ int age; int num; void print() { }}//先声明后实现namespace Boy { void print(); struct Info ;}struct Boy::Info { int data;};void Boy::print() {}int main() { return 0;}

命名空间| 访问

命名空间中的数据通过空间名和作用域分辨符::完成,作用域分辨符::还可以表示全局变量。如下测试代码:

#include <iostream>//直接实现namespace MM{  int age;  int num;  void print()   {  }}int g_num = 99;int main() {  int g_num = 88;  //默认就近原则  int x = g_num;    //使用全局  int y = ::g_num;  //1.空间名限定访问  MM::age = 123;  MM::print();  //2.省略前缀访问  //using namespace语句具有作用域  using namespace MM;  age = 123;  print();  return 0;}

using namespace 语句具有作用域,从使用处到第一次包含{}结束。

命名空间| 嵌套

命名空间嵌套使用剥洋葱的方式访问即可。如下测试代码:

#include <iostream>namespace Cool{ int a = 1; namespace Mo { int b = 2; namespace Ying { int c = 3; } }}int main() { Cool::a=11; Cool::Mo::b = 22; Cool::Mo::Ying::c = 33; { using namespace Cool; a = 111; Mo::b = 222; Mo::Ying::c = 333; using namespace Mo; b = 2222; Ying::c = 3333; using namespace Ying; c = 33333; } { using namespace Cool::Mo::Ying; c = 444; } return 0;}

命名空间| C++内置空间名std

在 C++ 中,std 是一个常用的内置命名空间,包含了大量的常用库函数和数据类型,例如 std::coutstd::stringstd::vector 等。这些函数和数据类型都位于 std 命名空间中,使用时需要通过 std:: 前缀进行引用。或者在写C++程序的时候,在头文件下面 直接使用:using namespace std; 有意思的是采用无后缀的包含C语言头文件后,C语言所有函数也可以采用std::使用。

如下测试代码:

#include <cstdio>int main() {  std::puts('coolmoying');  std::printf('coolmoying');  return 0;}

C++标准输入输出

在 C++ 中,标准输入输出通常使用 std::cinstd::cout 实现。这些对象是 C++ 标准库 <iostream> 中的对象,用于在标准输入和标准输出流之间进行输入输出数据交互。目前学会如何使用即可,无需追究那么多为什么,IO流操作中会介绍成员函数的使用方式,以及其他IO对象。

标准输入输出| 输出到屏幕

基本输出:cout加上 << 完成,需要掌握以下内容

  • 支持C语言转义字符
  • 输出单个数据
  • 输出多个数据
  • 换行: endl

如下测试代码:

#include <iostream>int main() { //C++也支持转义字符 std::cout << '字符串\n'; std::cout << 1; std::cout << 1.1f; std::cout << 1.1; std::cout << '\n'; std::cout << '字符串\n' << 1 << '\n' << 1.1 << '\n'; int a = 1; float b = 1.1f; char name[20] = { '张三' }; //输出多个数据,无需格式控制字符 std::cout << a << '\t' << b << '\t' << name << '\n'; std::cout << 'C++换行' << std::endl; //一般写在头文件下面 using namespace std; cout << '使用了using namespace std,无需std前缀' << endl; return 0;}

标准输入输出| 从键盘输入

基本输入: cin加上 >>完成,通常不需要任何格式控制字符,如下测试代码:

#include <iostream>int main() {  int a;  float b;  char name[20] = { '' };  std::cout << '请输入三个数据:';  std::cin >> a;  std::cin >> b;  std::cin >> name;  std::cout << a << '\t' << b << '\t' << name << std::endl;  //默认用空格或者换行作为数据间隔  std::cout << '请输入三个数据:';  std::cin >> a >> b >> name;  std::cout << a << '\t' << b << '\t' << name << std::endl;  return 0;}

C++新的基础类型

C++新基础类型|nullptr_t类型

nullptr_t 是 C++11 中引入的一个新的关键字,用于表示一个空指针常量的类型,是一种特殊的数据类型。当需要传递一个空指针常量给一个函数或作为一个函数返回值时,就可以使用 nullptr_t 来明确声明空指针常量的类型。C++空指针引入nullptr替换C语言中NULL,可以方便地编写出更加清晰、简洁和易于阅读的代码,避免出现空指针引用的错误,提高程序的可读性和安全性。如下测试代码:

#include <iostream>void func(std::nullptr_t ptr) { std::cout << 'coolmoying' << std::endl;}int main() { func(nullptr); //使用nullptr替换NULL int* p = nullptr; return 0;}

C++新基础类型|bool类型

在 C++ 中,bool 类型表示布尔值,仅包含两个值:truefalsebool 类型是 C++ 的基本数据类型之一,用于存储布尔值。C++ 的布尔类型提供了 bool 关键字来定义变量,bool 类型的变量可以作为条件表达式传递给 if 语句、while 循环等语句中,需要注意的是,C++ 中的 true 和 false 是关键字,不是任何标识符的名称。bool 类型赋值给其他类型时,false 转换为整型值 0,true 转换为整型值 1。其他类型的值赋值给 bool 时,非零值为 true,零值为 false。

如下测试代码:

#include <iostream>#include <iomanip>int main() {    bool close = true;    std::cout << 'bool类输出只有0和1:' << close << std::endl;    std::cout << '非零表示成立:' << close << std::endl;    std::cout <<std::boolalpha<< '打印true或false:' << close << std::endl;    close = -1;    return 0;}

程序运行结果如下:

文章图片2

C++新基础类型|不一样const类型

C++const比C语言const的要求更严格。当然const类型变量不能被修改并且创建的时候必须做初始化,这些依旧和C语言一样,主要区别在于字符串操作上。如下测试代码:

#include <iostream>void printStr(char* pstr){ std::cout << '只能传入变量,不能传入常量' << std::endl;}void printStrConst(const char* pstr){ std::cout << '只能传入变量,不能传入常量' << std::endl;}int main(){ //错误使用 //char* pstr='coolmoying'; //C++必须const修饰 const char* pstr = 'coolmoying'; //错误调用 //printStr('coolmoying'); //printStr(pstr); char str[] = { 'coolmoying' }; printStr(str); printStrConst(pstr); printStrConst(str); return 0;}

C++const比C语言更为强大,C++const可以修饰类中函数 ,具体后续讲解

C++新基础类型|引用类型

左值引用

在 C++ 中,引用是一种特殊的类型,用于给一个已经存在的变量取一个别名。引用可以简单理解为起别名的变量,一旦引用被定义,它将一直引用同一个变量。使用引用可以在函数中方便地传递变量、减少内存开销等。基本语法:type &name = variable; 如下测试代码:

#include <iostream>int main(){    int num = 1;    //number就是num,同一段内存不同名字    int& number = num;    number = 123;    std::cout << num << std::endl;    std::cout << number << std::endl;    return 0;}

常引用

在 C++ 中,常量引用是一个指向常量的引用。使用常量引用可以在不复制变量的情况下访问常量,并防止其修改。常量引用提供了一种方法来以只读方式引用已经存在的常量数据。这可以避免对变量的误修改,并且在函数参数传递和函数返回值中使用常量引用可以减少内存开销。常量引用通常在函数传参和函数返回值中使用。基本语法:const type &name = variable; 如下测试代码:

#include <iostream>void print(const int& num) { std::cout << '传普通变量或常量' << std::endl;}void printData(int& num){ std::cout << '只传普通变量' << std::endl;}int main(){ const int num = 10; //错误用法 //int& number = num; const int& number = num; //错误代码,常量不可修改 //number = 123; int data = 123; const int& xData = data; //const修饰的引用,不能修改 //xData = 123; //函数传参即可传入常量和变量 print(1); print(number); print(data); //只可传入常量 printData(data); //错误调用 //printData(number); //printData(1); return 0;}

右值引用

在 C++ 中,右值引用是 C++11 新增的特性,属于引用类型。与左值引用不同,右值引用是一个指向临时对象(右值)的引用。右值是指无法被赋值或访问地址的临时对象,右值引用可以为这些临时对象提供一个有效的引用,从而允许使用更有效的 C++ 编程技术来处理它们。基本语法:type &&name = variable; 如下测试代码:

#include <iostream>void print(int&& right) {}int main(){    int&& rigthvalue = 123;     int age = 0;    //错误调用    //print(age);    print(123);    return 0;}

std::move函数

在 C++11 中,std::move 是一个重载函数,用来支持右值引用语法的实现。std::move 接受一个对象,并将其转换成右值引用类型。通过调用 std::move 函数,我们可以显式地将一个具有名称的对象转换为右值引用,并从该对象到达一个新的右值引用对象。这样做的主要目的是为了可以在不拷贝数据的情况下将数据传递给新的对象。也就是说,std::move 可以将一个左值转换为右值,让程序能够更加高效地利用资源。在开发中,std::move 主要用于资源管理、移动语义和环境的构建。如下测试代码:

#include <iostream>void print(int&& right) {}int main(){ int&& rigthvalue = 123; int age = 0; //错误调用 //print(age); print(std::move(age)); print(123); return 0;}

引用折叠

在 C++11 引入的右值引用的特性中,引用折叠是一个非常重要的概念。引用折叠指的是在特定情况下,通过遵守一些简单的规则,可以使用两个引用声明名称新的别名,并将其和现有的引用类型组合成一个新类型。引用折叠规则如下:

  • 当左值引用(Lvalue reference)和左值引用组成一个新类型,结果仍然是左值引用。
  • 当右值引用(Rvalue reference)和左值引用组成一个新类型,结果仍然是右值引用。
  • 当右值引用和右值引用组成一个新类型,结果是右值引用。

引用折叠的一个重要的应用场景是在使用模板时,可以统一地处理左值引用和右值引用。如下测试代码:

#include <iostream>int main(){    typedef int&& Type;    int num = 0;    //等效 int& a=num;    Type& a = num;       //等效 int&& b=123;    Type&& b = 123;    return 0;}

引用折叠的规则在 C++ 模板编程中特别有用,因为我们可以将一个泛型实参视为一个“引用”,从而同时处理左值和右值引用。例如,在泛型算法 std::move() 中使用了引用折叠的技巧,可以将一个任意类型对象转换为右值引用,以便能够使用右值语义来操作对象。目前简单了解一下。

C++新基础类型|自动推断类型

在 C++11 中,引入了自动类型推断(type inference)的特性,该特性允许编译器在某些情况下自动推断变量的类型,从而避免了使用显式类型声明和指定的麻烦和冗长。这可以让我们更加方便快捷地定义变量和编写代码。C++ 中实现自动类型推断主要有两种语法:

  • auto 关键字:使用 auto 关键字来推断变量的类型,编译器会自动根据初始化表达式的类型推断出变量的类型。
  • decltype 关键字:使用 decltype 关键字来推断变量的类型,可以获取表达式的类型(包括变量类型、函数返回值类型等)。

在使用自动类型推断时,需要注意以下几点:

  • 自动类型推断只适用于变量的定义,不能用于函数的返回类型或参数类型;
  • 在定义变量时,使用自动类型推断可以简化代码,但可能会降低代码可读性;
  • 自动类型推断可以降低编译时的编译时长,因为编译器无需写出完整的类型声明来进行类型检查。

总之,自动类型推断是 C++11 中一个重要的特性,它可以让我们更方便地定义变量,避免了繁琐的类型声明,同时也可以提高代码的可读性和效率,并减少代码中的出错率。但是,在使用自动类型推断时,我们也需要遵循一些规则,保证代码的正确性和可读性。如下测试代码:

#include <iostream>struct MM { int age; char name[20];};int main(){ int num = 111; auto p1 = # decltype(&num) p2 = # MM mm = { 18,'baby' }; auto pMM = &mm; //错误用法 // auto必须通过初始来推断 //auto pstr; return 0;}

C++函数思想

C++函数思想|函数内联

在 C++ 编程中,函数内联是一种编译器对于函数的特殊处理方式。函数内联可以在编译期间将函数的定义嵌入到函数调用点处,从而消除了函数调用的开销,提高了程序的运行效率。使用函数内联的主要好处是可以减少函数调用带来的开销,避免函数调用堆栈的推入和弹出,这对于一些短小精悍的函数特别有效。

C++ 中使用 inline 关键字来指定一个函数为内联函数。一般情况下,将函数定义与函数声明放在头文件中并使用 inline 关键字来修饰,可以让编译器自动对该函数进行内联优化。需要注意的是,在进行内联优化时,并不是所有的函数都适合进行内联。如果一个函数的计算量比较大,或者参数较多,内联将会使代码量变大、可维护性降低、编译器时间增加,反而会导致程序效率降低。在进行函数内联时,我们需要根据具体情况进行判断,谨慎地选择需要进行内联优化的函数。如下测试代码:

#include <iostream>inline int Max(int a, int b) {    return a > b ? a : b;}int main(){    std::cout << Max(1, 2) << std::endl;    return 0;}

C++函数思想|函数重载

在 C++ 中,函数重载(Function Overloading)是一种允许在同一作用域内声明多个具有相同名称但参数不同的函数的机制。通过函数重载,我们可以用一个函数名称实现多种不同的功能,这使得代码更加灵活和易于维护。

函数重载的规则和注意事项如下:

  • 函数名必须相同,但函数的参数列表必须不同。参数列表的不同包括参数的个数、类型和顺序。
  • 返回值类型不能作为函数重载的区分标志,因此不能通过返回值类型的不同来区别不同的函数。
  • 静态函数和非静态函数之间可以进行重载。
  • 当实参与形参的数量或类型不匹配时,编译器会自动查找最佳匹配的函数。如果找不到匹配的函数,则编译时将出现错误。

如下测试代码:

#include <iostream>//数目不同void print(int a) { std::cout << 'int' << std::endl;}void print(int a, int b) { std::cout << 'int,int' << std::endl;}//类型不同void print(char a,int b){ std::cout << 'char,int' << std::endl;}//顺序不同void print(int a, char b) { std::cout << 'int,char' << std::endl;}int main(){ print(1); print(1, 2); print('A', 1); print(1, 'A'); return 0;}

函数重载是一个非常有用的特性,可以优化代码的可读性和效率。通过函数重载,我们可以使用同一函数名实现不同功能的函数,而无需使用不同的函数名称。在实际编程中,我们可以根据具体情况选择是否使用函数重载来强化代码的可重用性和扩展性。

C++函数思想|函数缺省

在 C++ 中,函数参数的缺省(Default Arguments)是一种在函数参数列表中为参数提供默认值的机制。当调用带有缺省参数的函数时,如果没有为该参数传递值,则该参数将采用默认值。缺省必须从右往左缺省。通过使用函数缺省,我们可以简化函数接口,避免代码的冗余以及提高代码的灵活性。测试代码如下:

#include <iostream>int Sum(int a, int b = 0, int c = 0, int d=0){    return a + b + c + d;}//错误写法//int Sum(int a=0, int b = 0, int c = 0, int d)//int Sum(int a, int b = 0, int c , int d=0)int main(){    //a=1,b=0,c=0,d=0    std::cout << Sum(1) << std::endl;    //a=1,b=2,c=0,d=0    std::cout << Sum(1, 2) << std::endl;    //a=1,b=2,c=3,d=0    std::cout << Sum(1, 2, 3) << std::endl;    //a=1,b=2,c=3,d=4    std::cout << Sum(1, 2, 3, 4) << std::endl;    return 0;}

函数缺省是 C++ 中重要的一个特性,它可以为参数列表中的参数提供默认值,使得使用函数变得更加便捷、自然和安全。在实际开发中,我们可以利用函数缺省来减少代码重复、提高代码的可维护性以及增强代码的灵活性。

相关

如果阁下正好在学习C/C++,看文章比较无聊,不妨关注下关注下小编的视频教程,通俗易懂,深入浅出,一个视频只讲一个知识点。视频不深奥,不需要钻研,在公交、在地铁、在厕所都可以观看,随时随地涨姿势。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多