c++语言的特点

C++语言是在C语言的基础上发展而来,同时它又支持面向对象的程序设计,它主要具有以下特点:

1.继承自C语言的优点:语言简洁、紧凑,使用方便、灵活;拥有丰富的运算符;生成的目标代码质量高,程序执行效率高;可移植性好等。

2.对C语言进行的改进:编译器更加严格,引入引用的概念,引入const常量和内联函数,取代宏定义等。

3 .同时支持面向过程和面向对象的方法:在C++环境下既可以进行面向对象的程序设计,也可以进行面向过程的程序设计。因此它也具有数据封装和隐藏、继承和多态等面向对象的特征。

(1)支持面向对象编程机制,如信息隐藏、封装函数、抽象数据类型、继承、多态、函数重载、运算符重载、乏型编程(模板)

(2)兼容C语言

(3)扩充C语言,如内联函数、函数重载、名字空间、更灵活、方便的内存管理(new、delete)、引用。

(4)团队开发更简单

C++语言既保留了C语言的有效性、灵活性、便于移植等全部精华和特点,又添加了面向对象编程的支持,具有强大的编程功能,可方便地构造出模拟现实问题的实体和操作;编写出的程序具有结构清晰、易于扩充等优良特性,适合于各种应用软件、系统软件的程序设计。用C++编写的程序可读性好,生成的代码质量高,运行效率仅比汇编语言慢10%~20%。

C++语言具有以下特点:

C++是C语言的超集。它既保持了C语言的简洁、高效和接近汇编语言等特点,又克服了C语言的缺点,其编译系统能检查更多的语法错误,因此,C++比C语言更安全。

C++保持了与C语言的兼容。绝大多数C语言程序可以不经修改直接在C++环境中运行,用C语言编写的众多库函数可以用于C++程序中。

支持面向对象程序设计的特征。C++既支持面向过程的程序设计,又支持面向对象的程序设计。

C++程序在可重用性、可扩充性、可维护性和可靠性等方面都较C语言得到了提高,使其更适合开发大中型的系统软件和应用程序。

C++设计成静态类型、和C同样高效且可移植的多用途程序设计语言。

C++设计成直接的和广泛的支援多种程序设计风格(程序化程序设计、资料抽象化、面向对象程序设计、泛型程序设计)。

C++设计成给程序设计者更多的选择,即使可能导致程序设计者选择错误。

C++设计成尽可能与C兼容,籍此提供一个从C到C++的平滑过渡。

C++避免平台限定或没有普遍用途的特性。

C++不使用会带来额外开销的特性。

C++设计成无需复杂的程序设计环境。
 

下面是一篇文章中提到的一些   https://blog.csdn.net/feiyagogogo/article/details/79573753 

(1)拥有虚函数的类会有一个虚表,而且这个虚表存放在类定义模块的数据段中。模块的数据段通常存放定义在该模块的全局数据和静态数据,这样我们可以把虚表看作是模块的全局数据或者静态数据,类的虚表会被这个类的所有对象所共享。类的对象可以有很多,但是他们的虚表指针都指向同一个虚表,从这个意义上说,我们可以把虚表简单理解为类的静态数据成员。值得注意的是,虽然虚表是共享的,但是虚表指针并不是,类的每一个对象有一个属于它自己的虚表指针。虚表中存放的是虚函数的地址。

(2)表格中的virtual functions地址是如何被建构起来的?在C++中,virtual functions(可经由其class object被调用)可以在编译时期获知。此外,这一组地址是固定不变的,执行期不可能新增或替换之。由于程序执行时,表格的大小和内容都不会改变,所以其建构和存取皆可以由编译器完全掌控,不需要执行期的任何介入。
(3)虚表指针则是在进入构造函数主体前被初始化的,(这个工作是编译器做的,对程序员来说是透明的),我们可以把构造函数的调用过程细分为两个阶段,即:1.进入到构造函数体之间。在这个阶段如果存在虚函数的话,虚表指针被初始化。如果存在构造函数的初始化列表的话,初始化列表也会被执行。2.进入到构造函数体内。这一阶段是我们通常意义上说的构造函数。
(4)由于虚函数的调用需要靠虚表指针获取虚函数地址,因此如果将构造函数声明为虚函数,会导致在虚表指针未初始化前即试图使用,从而产生错误。而析构函数则一般要声明为虚函数,在子类构造时,会先执行父类默认构造函数,再执行子类构造函数,而析构则相反,如果析构函数不为虚函数,则在多态(父类指针指向子类对象)析构时,会因无法动态绑定而只调用父类析构函数而不调用子类析构函数。
(5)C++在公有继承时,子类会继承父类的所有成员变量与方法(包括私有变量与私有成员函数),只是对于父类的私有成员,子类并无访问权限,因此在子类中这部分被隐藏了,这可以用一个空类继承来验证,通过查看sizeof(继承的空类的值)可以判断子类是否继承了父类的私有变量。
(6)sizeof(非继承的空类) = 1,这是因为实例化的原因(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址,所以空类所占的内存大小是1个字节。而当类非空时,使用sizeof计算将不会将这一个隐藏字节计入结果中。
(7)对于delete与delete [] 常理中的认识是单个变量使用delete数组则使用delete [],但实际上,对于基本类型(如float,int,double)delete与delete []的效果是一样的:

1    int *p = new int[10];
2    delete p;   //is same to delete [] p



单对于非基本类型,如对象数组,如果仅仅只是delete就可能会产生问题,因为对于对象的delete还需要不同于基本类型的一步——调用析构函数,因此如果只是delete将只会调用数组中第一个元素的析构函数,这样就有可能造成内存泄漏。

如果在C++类构造造函数中使用了初始化列表的语法,那么初始化的顺序与成员变量声明顺序相同,而与初始化列表的顺序无关,比如下图的初始化顺序为n2,n1而非n1,n2

class A    
{    
private:    
    int n2;    
    int n1; 

public:    
    A() :n1(0), n2(0){}   
};


C++使用inline来声明内联函数,这是为了在函数调用处能够直接展开函数代码而避免函数语句较少却因参数传递等代价带来的效率损失,但要注意的是,inline的声明只是用户希望这个函数内联,而编译器有权忽略这个请求。比如当函数语句十分长时,这时候函数的参数传递等开销对函数执行本身而言微不足道,如果还是在调用处展开会造成代码体积的膨胀,从而增大指令的存储空间,得不偿失,因此,对于教长的函数,编译器可能会忽略inline的请求,事实上内联函数也不应该用于较多语句的函数。
如果内联函数的声明在头文件中则头文件中不仅要包含 inline 函数的声明,而且必须包含定义,且在定义时必须加上 inline 。【关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用】
inline 函数可以定义在源文件中,但多个源文件中的同名 inline 函数的实现必须相同。一般把 inline 函数的定义放在头文件中更加合适。
定义在Class声明内的成员函数默认是inline函数:
class A {   public:  void Foo(int x, int y) { ... }   // 自动地成为内联函数   } 
结构体内存对齐的3大规则: 
1.对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍 
2.结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍 
3.如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型

C++传递参数是如果是按值传递,则会产生一个临时的变量副本(如果传递一个有拷贝构造函数的对象则会调用拷贝构造函数来构造这个对象),如果是按引用传递,则直接传递所引用变量的地址。

C++返回值与传递类似,如果返回的是一个引用,则直接返回所引用变量的本身(可能是通过返回地址实现,不同编译器实现可能不同),如果返回值非引用,则可能会在函数返回的函数处(比如A函数调用B函数,那么B函数返回的函数为A)分配空间创建一个临时变量(同样会调用拷贝构造函数),也可能直接将返回值存入寄存器(比如对于比较简单的基本类型)同样不同编译器实现不同。
#include<> 和 #include”” 只是最先搜索的路经不一样。#include<> :表示只从从标准库文件目录下搜索,对于标准库文件搜索效率快。#include”” :表示首先从用户工作目录下开始搜索,对于自定义文件搜索比较快,然后搜索整个磁盘(标准库)。
在类中 new A与new A()都会调用默认构造函数,但不同的是,当没有为类A提供默认构造或析构函数时(即类A的构造与析构函数由编译器生成,此时认为A是POD类型),则new A()会自动对成员变量初始化(比如把int初始化为0),当为类A提供了默认构造函数,即使提供的默认构造函数什么都不做,此时认为类A是non-POD类型,则new A不会对成员变量初始化。
当一个变量被明确声明为数组时,比如int a[5];则sizeof(a)计算的是数组所有元素所占的字节,上述例子结果为4∗5=204∗5=20 但当数组是用指针来描述的时候,比如int *p = new int[5];则sizeof计算的是指针的字节而非数组所有元素所占的字节,此外,数组的传参一般也是以指针形式描述,一般有int a[],int size;或int *a两种写法,后一种sizeof计算的依然是指针,而前一种,由于并不知道数组a的长度,因此大部分的实现中sizeof还是将a认为是指针并产生一个warning告诉你sizeof(a)将以指针的方式计算。
当类中含有其他类成员变量(这个成员类有默认构造函数)时,若这个类没有默认构造函数,则编译器自动产生的默认构造函数将会调用这个类成员变量的默认构造函数,如果用户定义了默认构造函数却没有在其中显式调用类成员变量的默认构造函数,则编译器会自动插入调用成员类默认构造函数的代码段,并且是在插入在原默认构造函数体的所有执行语句之前,当有多个类成员变量(均有默认构造函数)时,插入的顺序与声明顺序相同。
 

猜你喜欢

转载自blog.csdn.net/ypshowm/article/details/89240902