百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

C语言与C++的华山论剑(到底哪个厉害)

toyiye 2024-04-07 14:12 34 浏览 0 评论

  • C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制)。

  • C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。

  • (加群:590750544 学习c语言c++游戏开发——群里有大量游戏开发教学视频)

所以C与C++的最大区别在于它们的用于解决问题的思想方法不一样。之所以说C++比C更先进,是因为“ 设计这个概念已经被融入到C++之中 ”。

对语言本身而言,C是C++的子集。《Effective C++》上说道,C++由四个部分组成: C、Object-Oriented C++、Template C++、 STL,即c语言、面向对象OOP、泛型编程(模板)、STL。


面向对象OOP

面向对象的三个基本特征是:封装、继承、多态


封装

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

类的成员可以分为共有成员,私有成员,保护成员。在不考虑继承的情况下,保护成员与私有成员一样,都只能在类内部被访问;而存在继承的情况下,基类的保护成员根据继承的方式,相应地成为了子类的保护成员或私有成员,而基类的私有成员仍为基类的私有成员,子类无法访问基类的私有成员。


继承

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

通过继承创建的新类称为“子类”或“派生类”。

被继承的类称为“基类”、“父类”或“超类”。

继承的过程,就是从一般到特殊的过程。

在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

对基类的继承方式有三种:共有继承、私有继承、保护继承。

(1)共有继承:基类的共有成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有;

(2)私有继承:基类的共有成员和保护成员在派生类中成了私有成员,其私有成员仍为基类私有;

(3)保护继承:基类的共有成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。

ps:“其私有成员仍为基类私有”的意思是,基类的私有成员并没有成为派生类的私有成员,它仍然是基类的私有成员,只有基类的成员函数才能访问它,而不能被派生类的成员函数访问

在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。


多态

多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。

封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现接口重用。在C++中, 多态性体现在具有不同功能的函数可以使用同一个函数名,这样就可以通过一个函数名调用不同的函数内容。

实现多态,有二种方式,覆盖,重载。

  • 覆盖,是指子类重新定义父类的虚函数的做法。

  • 重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

关于虚函数,最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。

比如下面的例子:

#include <iostream>using namespace std;class person

{public: void sleep()

{ cout<<"person sleep"<<endl;

} virtual void get_up()

{ cout<<"person get up"<<endl;

}

};class student:public person

{public: void sleep()

{ cout<<"student sleep"<<endl;

} void get_up()

{ cout<<"student get up"<<endl;

}

};void main()

{

student ming;

person *ptr;

ptr = &ming;

ptr->sleep();

ptr->get_up();

ming.sleep ();

ming.get_up ();

}123456789101112131415161718192021222324252627282930313233343536123456789101112131415161718192021222324252627282930313233343536

运行结果为:

person sleep

student get up

student sleep

student get up12341234

同样,如果将一个子类的指针指向一个基类的对象,也可以调用相应的虚函数。只是没有使用虚函数,则调用子类的函数。如上面定义的类,若main函数为:

person we;student *ptr;ptr = (student *)&we;ptr->sleep();ptr->get_up();1234512345

则结果为:

student sleep

person get up

1、数据类型

C++标准只规定每种数据类型的最大值、最小值。至于用二进制编码表示,还是以BCD码表示并未规定,所以,对于不同的编译器,不同的造作系统(如:32位的以及64位的操作系统),每种数据类型所占用的字节数不一定相同。

Float为单精度浮点数,double为双精度浮点数。说明符用于修改数据类型具有的最大值、最小值。说明符有short,long, signed, unsigned。

2、指针的作用

设计指针时的一个很大动机就是在函数内部通过指针改变外部对象。在C++中除了指针又引进了一种新的对于地址的使用方式,即为引用。引用为对固定地址的传递,可以认为具有常量指针的某些特征—不能改变所指向的地址。使用引用使得对地址的传递更加方便。

指针的类型中的Void类型的使用比较特殊。Void类型的指针允许指向任何类型的数据类型。所以,在使用之前(即存取指向的地址位置的内容之前)必须对其进行强制的类型转换,增强了程序的灵活性。但是,Void类型的指针还是不提倡使用。因为,它可以将一种类型转化为另一种类型,所以,可能带来程序的奔溃。

3、变量的作用域

变量的作用域为从变量定义起始行到与定义该变量前一个最近一个开括号配对的第一个闭括号。

4、静态变量

静态变量同全局变量有一定的相似之处,他们都存在于整个生命周期,而不像局部变量只是在进入作用域时自动生成,离开作用域时自动消失。所以,同样可以用静态变量记录一些函数调用之间的片段信息。静态变量只在第一次调用时执行,函数调用之间变量的值保持不变。但是,静态变量的作用域范围则与全局变量不同,静态变量在其范围之外是不可用的,所以,可以使它不被外部的程序所破坏。当静态变量用于所有函数名和所有函数外部的变量时,它会将作用域限定在此文件范围以内。由于静态变量的作用域最多为文件域,所以,它不能与外部变量extern同时用于描述某一变量的特性。

5、外部变量

用于使用外部文件的一个变量,当在一个文件中看到extern的外部变量时,编译器即知道,在别的某个文件中或者本文件的后面存在在这样的一个变量的定义。

6、连接

有内部连接和外部连接。内部连接只对正在编译的的文件创建单独存储空间。用内部连接,别的文件可以使用相同的标识符或者全局变量,连接器不会发生冲突。

外部连接为所有编译过的文件建立一个单独的存储空间。通过用关键字extern声明,可以从别的文件访问此变量和函数。C++中默认将函数和全局变量定义为外部连接。

这里先介绍一下自由函数:如果一个函数为自由函数,那么该函数即不是类的成员函数也不是友元函数。

C++中有内部连接情况如下:

命名空间中的静态变量、静态自由函数、静态友元函数、常量的定义

Enum定义

Inline函数定义

声明

类的定义(同时,类的成员函数、变量在类的内部的声明永远都有内部连接)

Union的定义

友元函数为全局作用域,但是为内部连接属性。

C++中有外部连接的情况如下:

命名空间中的非静态变量、非静态自由函数、非友元函数

类中的静态成员变量

类的非inline成员函数的定义(即成员函数不是在类的内部定义,是在将成员函数的定义域声明分开)全都为外部连接

Main()为全局自由函数为外部连接,所以,不能有两个main()函数

内联函数总有内部连接。所以,类的内联成员函数的定义,最好放在定义本类的头文件中。若放到别的文件中在连接的时候就会产生找不到外部连接的错误。

7、常量

C++中可以使用const来定义某一个对象为常量,这一点与C是相同的。但是,他的作用域与C中的确大大不同。C++中如果用const定义某对象除了限制该对象不能被改变之外同普通变量一样有着自己对应的作用域。但是,C中却不是,在C中会为const创建存储空间,所以,如果在多个文件中定义相同名字的const常量则编译器将会报错0。在C++中一般将const定义放在头文件中,这样当有文件对它使用时,该文件只要包含此头文件。从而将const常量引入此文件,而此时编译器并不const常量分配存储空间。如果,一个常量被别的文件显式的用extern关键字所引用时,为了能被多个文件所使用,此时编译器必须要为常量分配空间,但是,一旦为此常量分配空间就意味着编译器此时不能知道此常量的值了(此时值存放在内存中),所以,也就不能使用常量折叠了。

由于const不能完全避免内存分配,所以,const默认为内部连接,从而将const常量域限制在文件内,这样避免被多个文件所引用,而致使在多个文件中分配内存,造成重复的分配内存。这样文件域中的const变量就可以在文件中用常量折叠。即使在单文件中const常量被迫分配了存储空间,但是由于const为内部连接属性,编译器知道常量值被保存到程序的某个地方,也知道const常量的值是不会改变的,所以,常量的值仍然是有效的,所以,仍然可以在此文件域中使用常量表达式以及常量折叠。

常量折叠:即编译时已经获得了这个变量的值(常量),这样就可以用这个常量去定义一些数组的大小等。如:int a[MAX];MAX为一个常量。

8、预处理宏 (加群:590750544 学习c语言c++游戏开发——群里有大量游戏开发教学视频)

宏可以方便程序参数的修改,节省输入时间。所调宏的地方预处理器都将用宏的定义所替换。但是,使用宏也有一定的风险——C++编译器对所有使用宏的地方不进行数据类型的检查。

9、运算符

位运算符,处理一个数中的个别位(因为浮点数采用一种特殊的内部格式,所以,运算符只适用于整型char int long)。

移位运算符,右移为<<,左移>>。移位时要注意是逻辑移位还是算数移位。

9、C++中的数据类型的转换

对一般的对象进行类型转换不会出现问题。但是对指针的类型的转化要特别的小心,如将指向一个占用存储空间小的变量转化为一个比他大的存储空间时,可能会破坏别的数据。

显式的类型转化:static_cast,用于良性、适度良性转换。包括编译器允许的做的,不用强制转换的“安全转换”以及不太安全但是清楚定义的变换。Const_cast用于对const和volatile的转换。Reinterpret_cast,就是当用的时候却发现,所得到的东西已经不同了,以至于他不能被用于类型原来的目的,除非把他转换回来,这个是最不安全的转换机制。

10、asm关键字、typedef关键字、struct关键字、枚举

Asm关键字用于在C++中嵌入汇编语言,用于高校调整以及特殊的处理器命令。Typedef,类型别名,用于节省输入,但大量使用会导致程序的可读性变差。Struct将基本的数据类型组合成复杂的数据类型。C++中的struct创建结构体时默认已经加入了typedef。所以,可以将struct所定义的数据结构当做基本的数据类型一样使用。结构体变量、以及结构体数组的使用和一般数据类型的变量和数组的使用方式相同,地址的取地址的方式也相同。&Stru取一个结构体变量的地址。&str[i]去一个结构体数组对象中某一个的地址。

枚举,即是将标识符与一整数联系起来,方便程序的阅读,但是由于存在不安全的类型转换。所以,在C++中很少使用。

11、union

使用联合的目的是减少内存的浪费,可以用一个变量来存放不同的数据类型,而联合的大小为联合中最大的数据类型的大小。在联合中存放数据时都是存储在联合的起始位置。所以,同一时间联合只能存放一个数据。

12、C++中的程序运行时的命令行参数

Int main(int argc , char * argv[]),其中argc用于记录命令行参数传递过来多少个参数,默认会将本程序的名字和路径放到第一个参数的位置,即argv[0]处。

此处提一下,在标准的C库的<cstdilib>中提供了atoi(),atol以及atof()。可以方便的将ASCII码很方便的转化为int,long,double浮点值。宏定义时,可以用“#参数”预处理命令将这参数转化为一个字符串。

13、指针的算数运算

指针会根据所指向的数据类型而动态的选择相应算术运算的基本单位。如int,double,float等。但是,两个指针的相加是没有意义的,编译器也不允许这样干。

14、C++中的main()函数的参数

Main函数有两个参数,int main(int agrc , char * argv[])第一个参数agrc为后面参数数组的大小。第二个参数中存放着由命令行输入的参数,默认数组的0号下标存放此执行程序的路径及名称。

15、调试技巧

调试标记,可以使用#define定义一个或者多个标记。根据这些标记可以测试一个使用

#ifdef

code

#endif

所限定的测试代码(code)。

Assert(argumnet)宏,也可以在代码中使用该宏来测试程序运行到本assert()时是否正常(argument(断言)是否预料的值)。如果正常则继续运行,否则发出一个错误消息,并告诉断言是什么以及失败之后将停止程序的运行。使用assert()断言需要包含C++语言cassert标准头文件。调试完成后在程序的#include<cassert>之前插入#define NDEBUG,就可以消除红产生的代码。

16、函数地址

函数在载入计算机时会占用一定的地址,所以,函数也有地址,也可以定义一个函数指针来指向某一个函数。如:void (*funcPtr)();为定义了一个指向无返回值,无参数的函数指针。定义函数指针时采用“从中间开始,向两边扩张,先右后左”的原则。如:

void *(*(*fp1)(int))[10]

表示为:fp1是什么——fp1是一个函数(右)——fp1是一个指向函数的指针(该函数有个int型的参数)(左)——fp1是一个指向函数的指针(该函数有个int型的参数)。该函数返回一个数组,数组的大小为10(右)——fp1是一个指向函数的指针。该函数返回一个指针数组,指针数组中的指针的类型为void类型,指针数组的大小为10。(左)。再如,

int (*(*f4())[10])()

为定义一个函数:f4是一个指向函数的指针,该函数返回一个大小为10的指针数组,指针数组中的指针指向一个函数,该函数返回一个int型值。如同数组的名字代表数组名字指向数组的地址一样,函数的名字也指向函数的地址。

17、指针常量和常量指针

指针常量:指针是一个变量,所以,它可以指向不同的常量,但是它指向的是一个常量,即它指向的地址不能存放别的值。

常量指针:指针是一个常量,它只能指向一个地址。而该地址是一个变量可以存放不同的值。

用法:常量指针:const * ptr,指针常量:* const prt

18、volatie关键字

用volatile关键字告诉编译器,这个变量是一个特殊地址。这个地址的内容可能被某些编译器未知的因素所修改。如:操作系统,多线程,汇编代码、硬件所改变。所以,告诉编译器不要优化该变量(每次对该变量的访问都从改变所在的地址访问,而非优化过的寄存器等)。来保持数据的一致性、有效性。

(加群:590750544 学习c语言c++游戏开发——群里有大量游戏开发教学视频)

此文为个人学习C++编程思想时个人心得体会,所以,难免有不严谨之处,甚至有可能是错误的理解。如发现错误,或者疑问。欢迎提出讨论,共同学习、进步

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码