C和C++的区别
1.语言类型:C 是一种过程性编程语言,着重于以函数为基础的结构化编程;而 C++ 是一种多范式编程语言,支持面向对象编程(OOP)和泛型编程等多种编程范式。
2.对象模型:C++ 支持类和对象的概念,可以通过封装数据和成员函数来实现面向对象编程。而在 C 中,没有直接支持类和对象的特性,只能通过结构体和函数来模拟。
3.标准库:C++ 在标准库方面相比 C 更加丰富。除了包括 C 标准库外,C++ 还提供了标准模板库(Standard Template Library,STL),其中包含了许多容器、算法和迭代器等可复用的组件,能够极大地简化开发过程。
4.面向对象特性:C++ 支持封装、继承和多态等面向对象编程的特性,使得代码可以更加模块化、可维护和可扩展。而在 C 中,没有原生的支持这些特性,需要手动进行实现。
5.异常处理:C++ 提供了异常处理机制,允许程序在出现错误时抛出异常,并通过异常处理语句进行捕获和处理。而在 C 中,通常使用错误码等方式来处理错误。
6.函数重载:C++ 支持函数重载,即可以定义多个同名函数,但参数类型、个数或顺序不同。这样可以根据具体的情况选择合适的函数进行调用。而在 C 中,函数重载是不允许的。
7.名称空间:C++ 引入了命名空间(namespace)的概念,可以避免命名冲突,在不同的名称空间中定义相同名字的函数和变量。C 中没有命名空间的概念
指针和引用
相同点:
1. 可以用于访问内存中的变量或对象。
2. 可以作为函数参数,传递变量或对象的引用或地址。
3. 可以用于动态分配内存,并在程序中进行内存管理。
4. 可以用于实现数据结构,如链表、树等。
5. 可以作为成员变量出现在类中,并用于实现类的数据成员和成员函数。
不同点:
1. 内存模型不同: 指针是一个变量,它存储着一个内存地址,而引用是一个别名,它是已经存在的变量或对象的别名。因此,指针本身占据内存空间,而引用不占用内存空间。
2. 指针和引用的自增(++)运算符意义不同,指针是对内存地址自增,而引用是对值的自增。
3. 指针需要解引用,引用使用时无需解引用(*).
4. 指针可以为空,引用不能为空。
5. “sizeof 指针”得到的是指针本身的大小,在32 位系统指针变量占用4字节内存,“sizeof 引用”得到的是所指向的变量(对象)的大小。
重载,重写,隐藏
#include <iostream>
using namespace std;
class A {
public: void Max(int a, int b){}
};
class B : public A{
public: int Max(char a){return 0;}
};
int main() {A Atest;Atest.Max(1,2);B Btest;Btest.Max('a'); // 正确调用Btest.Max(1,2); // 编译出错,虽然基类中的函数符合它的传入参数形式,但是基类中符合它类型的函数已经被隐藏了return 0;
}
new/delete,malloc/free的区别
1. new/delete是C++的关键字,操作符,可以被重载
2. malloc/free是C的库函数,不可以重载
3. malloc需要自己显示计算分配内存大小,new则由编译器计算
int *q = (int*)malloc(sizeof(int) * 2);int *p = new int[2];
4. malloc分配成功后返回的是void*指针,需要强制转换;new会直接返回对应的指针。
5. new/delete会调用构造,析构函数,malloc/free只会申请,释放内存,不调用构造/析构函数。
补充:delete,free后,需要将指针指向nullptr/NULL,因为内存不会立刻回收。
inline函数
1. 内联执行的内容,直接写在了调用处。
2. 不用像函数调用一样,直接执行函数体。
3. 相比较于宏,多了类型检查
4. 不能包含复杂操作,循环,递归,switch等。
5. Class中的函数,除了虚函数,自动隐式定义为内联
优点:
1. 直接在调用处代码展开,省去了参数压栈,回收等。
2. 代码展开时,相比较于宏,会做安全检查,自动类型转换
3. Class内自动转换为内联,可以访问成员变量
4. 可以调试,宏不行
this指针
隐含于非静态成员函数。this是一个右值,不可以取地址(&this不可以)。
堆和栈的区别
1. 栈,编译器管理;堆,用户管理;
2. 空间大小不同
3. 生长方式不同
4. 堆都是动态分配;栈有静态分配(编译器完成,比如局部变量),动态分配
静态全局变量、全局变量
1. 都位于常量区
2. 静态全局变量只在本文件中有效,别的文件无法使用;全局变量可以在别的文件中使用。
3. 不同文件不可以定义相同名称的全局变量。
静态局部变量和局部变量
1. 静态局部变量在常量区,局部变量在栈区
2. 静态局部变量作用域结束后,不会销毁,程序结束后才结束。
3. 静态变量初始值为0,局部变量是随机值
4. 静态局部变量编译时只赋值一次,以后每次调用相同函数,都不再赋值。
源代码如何变成可执行文件:预处理,编译,汇编,链接
预处理:删除所有的#define,处理所有条件预编译指令,如: #if, #ifdef, #else等。删除所有注释,添加行号,文件标识。.c文件 => .i文件
编译:编译器负责,词法分析,语法分析,语义分析等,最终生成目标机器代码, .s文件
汇编:将汇编语言转换为机器可以执行的语言(0,1组成),形成目标文件.o
链接:通过链接器将多个目标文件链接,生成可执行文件,连接器主要负责地址重新分配,符号名称绑定,重定位等。
map是否可以使用结构体作为key?
map自动排序,所以一般是不可以的,需要对<进行运算符重载。
如何定义一个只能在堆上(栈上)生成的类
只能在堆上:方法:将析构函数设置为私有。
原因:C++是静态绑定,编译器管理栈上对象的生命周期,编译器在为类分配空间时,会优先检查析构函数访问性,如果析构函数不可以访问,则不可以在栈上创建对象。
只能在堆上:方法:将new和delete重载为私有。
delete this是否合法
1. 必须保证this是new出来的。
2. delete this是最后一个调用this的语句。
如何判断程序是大端,小端
大端:高字节在低位(符合人的思维)
int main()
{short a = 0x1023;char b = static_cast<char>(a);if(b == 0x12) // 大端else if(b == 0x34) // 小端
}
内存分区模型
代码区:存放函数体的二进制代码,由操作系统进行管理
全局区:存放全局变量,静态变量以及常量
栈区:由编译器自动分配释放,存放函数的参数值,局部变量
堆:程序员分配释放
程序运行前:
编译生成可执行文件后,未执行该程序前分为两个区域:
代码区:存放CPU执行的机器指令,代码区是共享的,代码区是只读的。
全局区:全局变量,静态变量存放在此。
程序运行后:
栈区:由编译器自动分配释放,存放函数的参数值,局部变量。
extern "C"作用
按照C语言的方式编译,比如C是不支持重载的。
C++中struct和class的区别
1.权限分为成员访问权限和继承权限
默认成员权限:class是私有的,struct是公有的
默认继承权限:class是private,struct是public
2.class可以定义模板参数 template<class T>,而没有template<struct T>
3.C语言中:struct是用户自定义数据类型(UDT);C++中struct是抽象数据类型(ADT),支持成员函数的定义,(C++中的struct能继承,能实现多态)
C中struct是没有权限的设置的,且struct中只能是一些变量的集合体,可以封装数据却不可以隐藏数据,而且成员不可以是函数。
C++中,struct增加了访问权限,且可以和类一样有成员函数,成员默认访问说明符为public(为了与C兼容)。
struct作为类的一种特例是用来自定义数据结构的。一个结构标记声明后,在C中必须在结构标记前加上struct,才能做结构类型名(除:typedef struct class{};);C++中结构体标记(结构体名)可以直接作为结构体类型名使用,此外结构体struct在C++中被当作类的一种特例。
nullptr和NULL
在C语言中,NULL是宏定义,nullptr是C++ 11的关键字。
//C语言中NULL定义
#define NULL (void*)0 //c语言中NULL为void类型的指针,但允许将NULL定义为0//c++中NULL的定义
#ifndef NULL
#ifdef _cpluscplus //用于判定是c++类型还是c类型
#define NULL 0 //c++中将NULL定义为整数0
#else
#define NULL ((void*)0) //c语言中NULL为void类型的指针
#endif
#endif
c++中int *p=NULL; 实际表示将指针P的值赋为0,而c++中当一个指针的值为0时,认为指针为空指针。
strlen和sizeof的计算
1. strlen函数只可以以char*为参数,返回str的长度,不包括'\0'。
2. sizeof,计算实际字节数
const char* s1 = "0123456789";std::cout << sizeof(s1) << std::endl; // 根据编译器,返回地址字节数std::cout << sizeof(*s1) << std::endl; // 第一个字符字节数,1std::cout << strlen(s1) << std::endl; // s1的长度,10#######################################################################const char s2[] = "0123456789"; // 动态数组std::cout << sizeof(s2) << std::endl; // 11, 计算的是整个数组大小,会算上'\0'std::cout << strlen(s2) << std::endl; // 字符串长度,10std::cout << sizeof(*s2) << std::endl; // 1,计算第一个字符#######################################################################const char s3[100] = "0123456789";std::cout << sizeof(s3) << std::endl; // 100, 实际分配的内存大小std::cout << strlen(s3) << std::endl; // 10, 字符串长度#######################################################################int s4[100] = { 0,1,2,3,4 }; // int 4字节, 400字节std::cout << sizeof(s4) << std::endl;#######################################################################char p[] = { 'a', 'b', 'c', 'd' };char q[] = { 'a', 'b', '\0', 'c', 'd'};std::cout << sizeof(p) << std::endl; // 4字节std::cout << strlen(p) << std::endl; // ??不确定,随机数std::cout << sizeof(q) << std::endl; // 4字节std::cout << strlen(q) << std::endl; // 2, 相当于统计了ab
内存对齐
struct Stu{int i;int j;char k;}Stu test;std::cout << sizeof(test) << std::endl; // 输出12,字节对齐后12,4 or 8的倍数