赞
踩
总结,主要有这么几点不同:
1.struct 是值类型,class 是对象类型
2.struct 不能被继承,class 可以被继承
3.struct 默认的访问权限是public,而class 默认的访问权限是private.
4.struct总是有默认的构造函数,即使是重载默认构造函数仍然会保留。这是因为Struct的构造函数是由编译器自动生成的,但是如果重载构造函数,必需对struct中的变量全部初始化。并且Struct的用途是那些描述轻量级的对象,例如Line,Point等,并且效率比较高。class在没有重载构造函数时有默认的无参数构造函数,但是一被重载些默认构造函数将被覆盖。
5.struct的new和class的new是不同的。struct的new就是执行一下构造函数创建一个新实例再对所有的字段进行Copy。而class则是在堆上分配一块内存然后再执行构造函数,struct的内存并不是在new的时候分配的,而是在定义的时候分配
1.为什么要内存对齐:因为处理器读写数据,并不是以字节为单位,而是以块(2,4,6,8,16字节)为单位进行的,如果不进行内存对齐,本来只需要一次进行的访问,可能要好几次才能完成。
32位cpu一次能最多处理的信息是32bit位,如果你没有指定对齐,我们假设这样的数据结构在内存中存在的情况
typedef strutc test{
char a;
int b;
char c;
}
对应的在内存中存放的方式可能是这样(假定32位下):
那么,这样一来,取得这个int型变量需要经过两次的寻址,拼凑成一个完整的4字节的数。这个过程还涉及到cpu指令集调用和总线的读写操作,如果真是没有对齐的话,效率会差到不知道哪儿去了。
所以这个内存对齐是必须遵守的,为了提高cpu访问效率和速度。
2.内存对齐的原则:
例3 struct S1 { char a; // 1 char b; // 1 int c; // 4 }; printf("%d\n", sizeof(struct S1)); 例4 struct S2 { char a; // 1 int b; // 4 char c; // 1 }; printf("%d\n", sizeof(struct S2));
对于s1:a占用一个字节,偏移量是1,b是char型,占一个字节,偏移量1是这一个字节的整数倍,所以b放在a后面,现在偏移量是2,c是int型,占四个字节,2不是4的整数倍,所以在b后面填充两个字节,现在的偏移量就是4,是int类型的整数倍。所以int的起始地址是4。
对于s2:a占用一个字节,偏移量为1,b占四个字节,所以a后面要预留3个字节。放完b后现在的偏移量是8,c占1个字节,直接放在b的后面。而结构体的内存必须为结构体内最大成员的最小整数倍,结构体内最大成员是b,占四个字节,所以结构体的大小必须为4的整数倍,所以c后面要留三个字节大小。
1、联编
联编就是把函数名与函数体的程序代码连接(联系)在一起的过程。
静态联编就是在编译阶段完成的联编。静态联编函数调用速度很快。效率高, 但缺乏灵活性;
动态联编是运行阶段完成的联编。动态联编在运行时才能确定调用哪个函数,它降低了程序的运行效率,但增强了程序的灵活性。
2、多态
编译时多态是通过静态联编来实现的。编译时多态性主要是通过函数重载和运算符重载实现的。
运行时多态是通过动态联编实现的。运行时多态性主要是通过虚函数来实现的。
第一:private,public,protected方法的访问范围.(public继承下)
private: 只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问.
protected: 可以被该类中的函数、子类的函数、以及其友元函数访问,但不能被该类的对象访问
public: 可以被该类中的函数、子类的函数、其友元函数访问,也可以由该类的对象访问
第二:类的继承后方法属性变化:
使用private继承,父类的所有方法在子类中变为private;
使用protected继承,父类的protected和public方法在子类中均变为protected;而private方法不变;
使用public继承,父类中的方法属性不发生改变;
注意:虽然子类无法直接访问基类的private成员,但是子类也继承了父类的私有成员,子类可以通过调用父类的非私有的成员函数调用基类的私有成员
初始化列表以冒号开始,形式为 变量名(初值),多个变量之间以逗号分隔。
初始化列表的用处在于,它可以对const修饰的常量进行初始化。而若写在大括号中,是在计算阶段赋值,而常量是不能在计算阶段进行赋值的。
初始化列表只能用于构造函数中,无论是普通构造函数还是拷贝构造函数。
成员变量中含有常量时,只能用初始化列表进行初始化。
不建议在构造函数中抛出异常。当构造函数中抛出异常时,析构函数将不会被执行,需要手动释放内存。但是构造函数是可以抛出异常的。
析构函数不应该抛出异常。当析构函数中有一些可能发生的异常时,这时候要把可能发生的异常完全封装在析构函数内部,决不能让它抛出到函数之外。C++标准指明析构函数不能、也不应该抛出异常。
抛出异常详解
构造函数不可以是虚函数。因为类的虚函数表指针是在构造函数中初始化的,在虚表指针没有被正确初始化之前,我们不能调用虚函数。
构造函数和析构函数也不能调用虚函数,前者是因为虚表指针还没有被初始化,后者是因为虚表指针可能已经被析构了。
讲讲移动构造函数与拷贝构造函数的区别:移动构造函数是c++11的新特性,移动构造函数传入的参数是一个右值 用&&标出。一般来说左值可以通过使用std:move方法强制转换为右值。首先讲讲拷贝构造函数:拷贝构造函数是先将传入的参数对象进行一次深拷贝,再传给新对象。这就会有一次拷贝对象的开销,并且进行了深拷贝,就需要给对象分配地址空间。而移动构造函数就是为了解决这个拷贝开销而产生的。移动构造函数首先将传递参数的内存地址空间接管,然后将内部所有指针设置为nullptr,并且在原地址上进行新对象的构造,最后调用原对象的的析构函数,这样做既不会产生额外的拷贝开销,也不会给新对象分配内存空间。
而对于指针参数来讲,需要注意的是,移动构造函数是对传递参数进行一次浅拷贝。也就是说如果参数为指针变量,进行拷贝之后将会有两个指针指向同一地址空间,这个时候如果前一个指针对象进行了析构,则后一个指针将会变成野指针,从而引发错误。所以当变量是指针的时候,要将指针置为空,这样在调用析构函数的时候会进行判断指针是否为空,如果为空则不回收指针的地址空间,这样就不会释放掉前一个指针。
区别
1) 引用必须被初始化,指针不必。
int ival=1024;
int &refval=ival; //refval指向ival(是ival的另一个名字)
int &refval2; //报错,引用必须初始化
因为一般在初始化变量时,初始值会被拷贝到新建立的对象中。不过在定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用则绑定到它的初始化对象上。不能更改绑定的对象,因此引用必须初始化。
2) 引用初始化以后不能被改变,指针可以改变所指的对象。
3) 不存在指向空值的引用,但是存在指向空值的指针。
1.C语言面向过程,C++面向对象
面向过程:面向过程编程就是分析出解决问题的步骤,然后把这些步骤一步一步的实现,使用的时候一个一个的依次调用就可以了。
面向对象::面向对象编程就是把问题抽象成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
2、后缀名不同
3.返回值
C语言中,如果一个函数没有指定返回值类型,默认返回int类型;C++中,如果一个函数没有返回值则必须指定为void。
4.关键字不同
C99有32个关键字
C++98有63个关键字
一些关键字的细微区别:
(1)struct:在C语言中struct定义的变量中不能有函数,而在C++中可以有函数。
(2)malloc :malloc函数的返回值为void*,在C语言中可以赋值给任意类型的指针,在C++中必须强制类型转换,否则报错。
(3)struct和class:class是对struct的扩展,struct默认的访问权限是public,而class默认的访问权限是private。
5.函数重载
函数重载:函数重载是函数的一种特殊情况,指在同一作用域中,声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数、类型、顺序)必须不同,返回值类型可以相同也可以不同,常用来处理实现功能类似数据类型不同的问题。(C语言没有函数重载,C++支持函数重载)。
6.缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的参。(C语言不支持缺省参数)
1、封装
通过封装将一部分成员隐藏起来,另一部分成员作为类或对象与外部的接口。从而控制数据的访问权限,并且能够减少程序中不同部分之间的相互影响。隐藏对象的属性和接口实现细节,仅仅对外提供接口和方法。
优点:提高安全性,隔离影响。
2、继承
在父类基础上创建派生类,可以通过增加、修改、替换父类成员产生派生类,对父类进行扩充,这种继承性使程序具有可重用性。子类可以从父类中获得同类的本质特征,并且增加个体特征,而不必完全重新定义。
优点:提高代码重用性。
子类会继承父类的哪些数据?
子类会继承父类除了构造函数、拷贝构造函数和析构函数以外所有的非静态成员.
注意:虽然父类的private成员在子类中无法访问到,但是仍然继承到了子类中,这些成员只是被隐藏了.
3、多态
多态体现在两个方面,动态联编和静态联编,分别指 在程序运行时的多态 和 在程序编译时的多态。
动态联编:在子类中 重写 基类的虚函数,使用 基类指针 或者 基类引用 指向子类对象时,可以实现不同的功能。
静态联编:使用 普通的函数重载 或者 函数模板的使用,实现调用同名函数实现不同功能。
优点:提高代码重用性,提高可扩展性
代码区:存放程序的代码,即CPU执行的机器指令,并且是只读的。
常量区:存放常量(程序在运行的期间不能够被改变的量,例如: 10,字符串常量”abcde”, 数组的名字等)
静态区(全局区):静态变量和全局变量的存储区域是一起的,一旦静态区的内存被分配, 静态区的内存直到程序全部结束之后才会被释放
堆区:由程序员调用malloc()函数来主动申请的,需使用free()函数来释放内存,若申请了堆区内存,之后忘记释放内存,很容易造成内存泄漏
栈区:存放函数内的局部变量,形参和函数返回值。栈区之中的数据的作用范围过了之后,系统就会回收自动管理栈区的内存(分配内存 , 回收内存),不需要开发人员来手动管理。栈区就像是一家客栈,里面有很多房间,客人来了之后自动分配房间,房间里的客人可以变动,是一种动态的数据变动。
垂悬指针:指针正常初始化,曾指向一个对象,该对象被销毁了,但是指针未制空,那么就成了悬空指针。
对于局部常量,存放在栈区;
对于全局常量,放在全局区/静态区
字面值常量,比如字符串,放在常量区。
extern的用法
Extern “C”是由C++提供的一个连接交换指定符号,用于告诉C++这段代码是C函数。这是因为C++编译后库中函数名会变得很长,与C生产的不一致,造成C++不能直接调用C函数,加上Extern “C”后,C++就能直接调用C函数了。(实现C与C++的混合编程)表示用到C语言中的变量或函数
1.内联函数的调用是传参,宏定义只是简单的文本替换
2.内联函数是在编译时展开的,宏定义在预处理阶段就进行替换了(因为虚函数是在运行时生效的,所以虚函数不能声明为内联的)
3.内联函数有类型检测更加的安全,宏定义没有类型检测
4.内联函数在运行时可调式,宏定义不可以
5.内联函数可以访问类的成员变量,宏不可以
6.在类中声明同时定义的成员函数,自动转化为内联函数。
宏的缺点:
1.宏没有类型检测,不安全
2.宏是在预处理时进行简单文本替换,并不是简单的参数传递(很难处理一些特定情况。例如:Add(z++))
3.使代码变长
4.宏不能进行调试
宏的优点:
1.提高程序可读性,方便进行修改
2.使用带参数的宏定义既可以完成函数调用的功能,又可以避免函数的出栈入栈操作,减少系统开销,提高运行效率
3.宏是由预处理器处理的,通过字符串操作可以完成很多编译器无法实现的功能,比如##连接符
内联函数的优点:
1.直接将代码插入调用处,减少普通函数调用时的资源消耗
2.有参数检测更安全
3.inline关键字只是对编译器的一个定义,如果函数不符合内联函数的标准,编译器就会把这个函数当成普通函数
内联函数的缺点:
1.使代码长度变长,文件变大
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。