【C++】从C语言到C++学习指南

embedded/2024/11/25 6:04:19/

如果你也是从C语言一路过来的,那么请一起看下去吧!

文章目录

  • 面型对象程序设计
  • C++基础
    • C和C++一些语法区别
    • C++在非对象方面对C语言的扩充
    • C++的一些标准(兼容旧标准)

首先,在C++的学习中,我们要时刻清醒一点:虽然C++与C语言有很大区别,但C++是C语言的扩充

说到C++和C语言的区别,那也是面向对象和面向过程的区别,这时你的老师可能会这么给你讲:

在这里插入图片描述

可是学了C语言没学过C++的人发问了:我们在学面向过程设计的时候,说“数据和操作往往都是分离的”,数据是米饭,操作是米饭上盖的菜,既然如此面向过程那不应该是盖饭吗?而面向对象具有封装的特点更是炒饭呀!(老师气的脸都绿了)

只有当你亲口尝了这两种饭菜,你才会知道盖饭中的菜是什么米是什么,炒饭中的菜是什么米是什么,以及他们的口味。所以,当你正确的理解了这个比喻,你便能真正认识C语言与C++,面向过程和面向对象,那么请跟随我一起去寻找我们的答案吧~

面型对象程序设计

面向过程是这样的:

img

一个程序是一道菜,面向过程这道菜的特点是:先从整体角度全面看待问题,然后列出解决问题需要的步骤,再逐步去完善。

面向对象是这样的:

img

面向对象这道菜有两个主要的结构特点:①程序一般由类的定义(属性)和类的使用(行为)两部分组成;②程序中的一切都是通过向对象发送消息来实现的,对象接收到消息后,启动有关方法完成相应的操作。

  • 对象:描述其属性的数据以及对这些数据施加的一组操作封装在一起构成的统一体。对象可认为是数据+操作。
  • :类是具有相同的数据和相同的操作的一组对象的集合。
  • 消息传递:对象之间的交互。
  • **方法:**对象实现的行为称为方法

面向对象程序设计的基本特征:抽象、封装、继承、多态。


理清了面向对象和面向过程之间的区别后,然我们来了解一下——从C语言到C++~

C++基础

C++的产生和特点

C++是美国贝尔实验室的Bjarne Stroustrup博士在C语言的基础上,弥补了C语言存在的一些缺陷,增加了面向对象的特征,于1980年开发出来的一种面向过程性与面向对象性相结合的程序设计语言。最初他把这种新的语言称为“含类的C”,到1983年才取名为C++。

相比C语言,C++的主要特点就是增加了面向对象机制!

一个简单的C++示例程序

#include<iostream>                 //编译预处理命令
using namespace std;               //使用命名空间void Log(const char* message) {    //函数定义cout << message << endl;
}int main() {Log("Hello World!");cin.get();
}

C和C++一些语法区别

1.三目运算符:在C语言中返回的是一个常量,是不能被赋值的;而C++中返回的是变量,可以被赋值

2.C++中的函数必须要写返回值类型

3.在全局下,C++不允许int a;int a=10;等这种重定义二义性操作

4.在C++中不要返回局部变量或临时变量的地址,虽然C++能够运行变量出作用域之后再使用一次,即C++允许在代码块中的任何地方声明局部变量。

5.C语言中const修饰的变量不能定义数组大小,而C++中可以

const int a=10;
float arr[a];
12

6.C++中定义结构体类型变量可以不用写结构体类型名

7.关于C语言有没有bool类型:C语言的布尔类型(bool)

C++在非对象方面对C语言的扩充

(1)输入和输出

int i;
float f;
cin >> i;
cout << f;
------------
scanf("%d", &i);
printf("%f", f);
----------------
连续读入
cin >> a >> b >> c;

【cin】

  • 在默认情况下,运算符“>>”将跳过空白符,然后读入后面与变量类型相对应的值。因此,给一组变量输入值时可用空格符、回车符、制表符将输入的数据间隔开。
  • 当输入字符串(即类型为string的变量)时,提取运算符“>>”的作用是跳过空白字符,读入后面的非空白字符,直到遇到另一个空白字符为止,并在串尾放一个字符串结束标志‘\0’。

(2)const修饰符

在C语言中,习惯使用#define来定义常量,例如#define PI 3.14,C++提供了一种更灵活、更安全的方式来定义常量,即使用const修饰符来定义常量。例如const float PI = 3.14;

const可以与指针一起使用,它们的组合情况复杂,可归纳为3种:指向常量的指针、常指针和指向常量的常指针。

  • 指向常量的指针:一个指向常量的指针变量。

    const char* pc = "abcd";
    该方法不允许改变指针所指的变量,即pc[3] = ‘x';   是错误的,
    但是,由于pc是一个指向常量的普通指针变量,不是常指针,因此可以改变pc所指的地址,例如pc = "ervfs";
    该语句付给了指针另一个字符串的地址,改变了pc的值。
    123456
    
  • 常指针:将指针变量所指的地址声明为常量

    char* const pc = "abcd";
    创建一个常指针,一个不能移动的固定指针,可更改内容,如pc[3] = 'x';
    但不能改变地址,如pc = 'dsff';  不合法
    12345
    
  • 指向常量的常指针:这个指针所指的地址不能改变,它所指向的地址中的内容也不能改变。

    const char* const pc = "abcd";
    内容和地址均不能改变
    12
    

说明:

  1. 如果用const定义整型常量,关键字可以省略。即 const in bufsize = 100const bufsize = 100等价;
  2. 常量一旦被建立,在程序的任何地方都不能再更改。
  3. 与#define不同,const定义的常量可以有自己的数据类型。
  4. 函数参数也可以用const说明,用于保证实参在该函数内不被改动。

(3)void型指针

void通常表示无值,但将void作为指针的类型时,它却表示不确定的类型。这种void型指针是一种通用型指针,也就是说任何类型的指针值都可以赋给void类型的指针变量

需要指出的是,这里说void型指针是通用指针,是指它可以接受任何类型的指针的赋值,但对已获值的void型指针,对它进行再处理,如输出或者传递指针值时,则必须再进行显式类型转换,否则会出错。

    void* pc;int i = 123;char c = 'a';pc = &i;cout << pc << endl;         //输出指针地址006FF730cout << *(int*)pc << endl;  //输出值123pc = &c;cout << *(char*)pc << endl; //输出值a

(4)内联函数

在函数名前冠以关键字inline,该函数就被声明为内联函数。每当程序中出现对该函数的调用时,C++编译器使用函数体中的代码插入到调用该函数的语句之处,同时使用实参代替形参,以便在程序运行时不再进行函数调用。引入内联函数主要是为了消除调用函数时的系统开销,以提高运行速度。

说明

  • 内联函数在第一次被调用之前必须进行完整的定义,否则编译器将无法知道应该插入什么代码
  • 在内联函数体内一般不能含有复杂的控制语句,如for语句和switch语句等
  • 使用内联函数是一种空间换时间的措施,若内联函数较长,较复杂且调用较为频繁时不建议使用
#include <iostream>
using namespace std;inline double circle(double r)  //内联函数
{double PI = 3.14;return PI * r * r;
}int main() 
{for (int i = 1; i <= 3; i++)cout << "r = " << i << " area = " << circle(i) << endl;return 0;
}

使用内联函数替代宏定义,能消除宏定义的不安全性

(5)带有默认参数值的函数

当进行函数调用时,编译器按从左到右的顺序将实参与形参结合,若未指定足够的实参,则编译器按顺序用函数原型中的默认值来补足所缺少的实参。

void init(int x = 5, int y = 10);
init (100, 19);   // 100 , 19
init(25);         // 25, 10
init();           // 5, 10
1234
  • 在函数原型中,所有取默认值的参数都必须出现在不取默认值的参数的右边

    int fun(int a, int b, int c = 111);
    1
    
  • 在函数调用时,若某个参数省略,则其后的参数皆应省略而采取默认值。不允许某个参数省略后,再给其后的参数指定参数值。

(6)函数重载

在C++中,用户可以重载函数。这意味着,在同一作用域内,只要函数参数的类型不同,或者参数的个数不同,或者二者兼而有之,两个或者两个以上的函数可以使用相同的函数名。

#include <iostream>
using namespace std;int add(int x, int y)
{return x + y;
}double add(double x, double y)
{return x + y;
}int add(int x, int y, int z)
{return x + y + z;
}int main() 
{int a = 3, b = 5, c = 7;double x = 10.334, y = 8.9003;cout << add(a, b) << endl;cout << add(x, y) << endl;cout << add(a, b, c) << endl;return 0;
}

说明:

  • 调用重载函数时,函数返回值类型不在参数匹配检查之列。因此,若两个函数的参数个数和类型都相同,而只有返回值类型不同,则不允许重载。

    int mul(int x, int y);
    double mul(int x, int y);
    12
    
  • 函数的重载与带默认值的函数一起使用时,有可能引起二义性。

    void Drawcircle(int r = 0, int x = 0, int y = 0);
    void Drawcircle(int r);
    Drawcircle(20);
    123
    
  • 在调用函数时,如果给出的实参和形参类型不相符,C++的编译器会自动地做类型转换工作。如果转换成功,则程序继续执行,在这种情况下,有可能产生不可识别的错误。

    void f_a(int x);
    void f_a(long x);
    f_a(20.83);
    

(7)作用域标识符::

通常情况下,如果有两个同名变量,一个是全局的,另一个是局部的,那么局部变量在其作用域内具有较高的优先权,它将屏蔽全局变量。

如果希望在局部变量的作用域内使用同名的全局变量,可以在该变量前加上“::”,此时::value代表全局变量value,“::”称为作用域标识符。

#include <iostream>
using namespace std;int value;   //定义全局变量valueint main() 
{int value;  //定义局部变量valuevalue = 100;::value = 1000;cout << "local value : " << value << endl;cout << "global value : " << ::value << endl;return 0;
}

(8)强制类型转换

可用强制类型转换将不同类型的数据进行转换。例如,要把一个整型数(int)转换为双精度型数(double),可使用如下的格式:

int i = 10;
double x = (double)i;int i = 10;
double x = double(i);
12345

以上两种方法C++都能接受,建议使用后一种方法。

(9)new和delete运算符

程序运行时,计算机的内存被分为4个区:程序代码区、全局数据区、堆和栈。其中,堆可由用户分配和释放。C语言中使用函数malloc()free()来进行动态内存管理。C++则提供了运算符newdelete来做同样的工作,而且后者比前者性能更优越,使用更灵活方便。

指针变量名 = new 类型int *p;p = new int;
delete 指针变量名delete p;
12345

下面对new和delete的使用再做一下几点说明:

  • 用运算符new分配的空间,使用结束后应该用也只能用delete显式地释放,否则这部分空间将不能回收而变成死空间。

  • 在使用运算符new动态分配内存时,如果没有足够的内存满足分配要求,new将返回空指针NULL)。

  • 使用运算符new可以为数组动态分配内存空间,这时需要在类型后面加上数组大小。

    指针变量名 = new 类型名[下标表达式];
    int *p = new int[10];
    12
    

    释放动态分配的数组存储区时,可使用delete运算符。

    delete []指针变量名;
    delete p;
    12
    
  • new 可在为简单变量分配空间的同时,进行初始化

    指针变量名 = new 类型名(初值);
    int *p;
    p = new int(99);
    ···
    delete p;
    

(10)引用

引用reference)是C++对C的一个重要扩充。变量的引用就是变量的别名,因此引用又称别名

类型 &引用名 = 已定义的变量名
1

引用与其所代表的变量共享同一内存单元,系统并不为引用另外分配存储空间。实际上,编译系统使引用和其代表的变量具有相同的地址。

#include <iostream>
using namespace std;
int main() 
{int i = 10;int &j = i;cout << "i = " << i << " j = " << j << endl;cout << "i的地址为 " << &i << endl;cout << "j的地址为 " << &j << endl;return 0;
}

上面代码输出i和j的值相同,地址也相同。

  • 引用并不是一种独立的数据类型,它必须与某一种类型的变量相联系。在声明引用时,必须立即对它进行初始化,不能声明完成后再赋值。
  • 为引用提供的初始值,可以是一个变量或者另一个引用。
  • 指针是通过地址间接访问某个变量,而引用则是通过别名直接访问某个变量。

引用作为函数参数、使用引用返回函数值

#include <iostream>
using namespace std;void swap(int &a, int &b)
{int t = a;a = b;b = t;
}int a[] = {1, 3, 5, 7, 9};int& index(int i)
{return a[i];
}int main() 
{int a = 5, b = 10;//交换数字a和bswap(a, b);cout << "a = " << a << " b = " << b << endl;cout << index(2) << endl;   //等价于输出元素a[2]的值index(2) = 100;             //等价于将a[2]的值赋为100;cout << index(2) << endl;return 0;
}

对引用的进一步说明

  • 不允许建立void类型的引用
  • 不能建立引用的数组
  • 不能建立引用的引用。不能建立指向引用的指针。引用本身不是一种数据类型,所以没有引用的引用,也没有引用的指针。
  • 可以将引用的地址赋值给一个指针,此时指针指向的是原来的变量。
  • 可以用const对引用加以限定,不允许改变该引用的值,但是它不阻止引用所代表的变量的值。

C++的一些标准(兼容旧标准)

1.以初始化列表的方式赋值

int c{2};
int d{(int)3.3};
int arr1[6]{1,2,3};

2.空指针

int *p=NULL;//旧标准
int *p1=nullptr;//新标准

3.自动类型

auto x=10.6;//根据初始化赋值的类型决定变量的类型

4.decltype的使用:可以理解为 复制类型

int n=123;
decltype(n) m=100;//定义一个和变量n一样类型的变量m
decltype((n)) k=n;//给变量n取一个别名k,类似于引用 int& k=n;
123

5.给数据类型取别名

typedef int HP;//旧
using MP = int;//新
typedef void(*pFun)();//旧
using PFun = void(*)();//新
typedef char str[10];//旧
using Str = char[10];//新
123456

6.新的for循环语法规则

#include<iostream>
int main() {int arr2[10] = { 1,2,3,4,5,6,7,8,9,0 };for (int i = 0; i < 10; i++) {std::cout << arr2[i] << '\t';}std::cout<<std::endl;//新for (auto i : arr2) {std::cout << i << '\t';}
}

这个方法只能用来遍历数组或者容器,i所代表的是里面存储的数据元素。指针不能这样遍历。


好啦,下面我们就进入C++的系统学习吧!(笔者会陆续更新哦)

三大特点:

①封装——类和对象

②继承与派生

③多态性与虚函数

运算符重载

函数模版与类模版

C++的输入和输出

异常处理和命名空间

STL标准模板库


http://www.ppmy.cn/embedded/140304.html

相关文章

Java 实现PDF添加水印

maven依赖&#xff1a; <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.4.3</version> </dependency>网络地址添加水印代码&#xff1a; public static boolean waterMarkNet(Stri…

开源网络安全检测工具——伏羲 Fuxi-Scanner

伏羲是一款开源的网络安全检测工具&#xff0c;适用于中小型企业对企业信息系统进行安全巡航检测 本系统通过模块化提供多种安全功能 基于插件的漏洞扫描功能持续化漏洞管理多种协议的弱口令检测企业子域名收集企业 IT 资产管理及服务发现端口扫描AWVS(Acunetix Web Vulnerab…

C# 委托与事件

C# 委托 在C#中&#xff0c;委托&#xff08;Delegate&#xff09;是一种引用类型&#xff0c;用于封装方法的引用。它允许你将方法作为参数传递&#xff0c;或者将方法赋值给变量&#xff0c;从而实现方法的传递和调用。委托在C#中扮演着非常重要的角色&#xff0c;尤其是在事…

设计模式之 适配器模式

适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将一个类的接口转换成客户端所期望的另一个接口。通过使用适配器模式&#xff0c;原本由于接口不兼容的类可以进行协作。简单来说&#xff0c;适配器模式就是将不兼容的接口连接起来&…

java游戏账号交易系统.v1

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;游戏售卖网站当然也不能排除在外。游戏售卖网站是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#x…

Vision Transformer(VIT模型)

【11.1 Vision Transformer(vit)网络详解-哔哩哔哩】 https://b23.tv/BgsYImJ 工作流程&#xff1a; ①将输入的图像进行patch的划分 ②Linear Projection of Flatted patches&#xff0c;将patch拉平并进行线性映射生成token ③生成CLS token&#xff08;用向量有效地表示整…

【计算机网络】数据链路层

跨网络传输的本质&#xff1a;由许多局域网(子网)转发的结果 要彻底理解跨网络转发&#xff0c;首先要理解 -> 局域网中报文的转发原理&#xff01; ​​​​​​​ 一、以太网帧格式 1.报头的含义 源地址/目的地址&#xff1a;源MAC地址和目的MAC地址 帧协议类型&…

<硬件有关> 内存攒机认知入门,内存的选择 配置 laptop PC 服务器

原因 这不是黑五吗&#xff0c;给我儿子买了台最便宜 ($300) DELL laptop&#xff0c;CPU 是 i5-1235U&#xff0c;但只有 8GB 内存。升级内存吧。 如何选择内存&#xff1a;家用范围 这里不考虑品牌&#xff0c;在我眼里&#xff0c;区别就是价格&#xff0c;还有所谓的物理…