C++和Java的共性与区别
阅读本文的读者中,大多都有一定的Java基础,所以本文会建立在你有一定Java基础的情况下来讲解。首先C++支持的基础数据类型,运算符,控制流语句,类和对象这些和java基本一致。但C++还具有如下特性:
-
编程范式
:Java是一种面向对象的编程语言,注意是只支持;而C++同时支持面向对象编程和面向过程编程,因为继承了C语言的特点。这意味着C++可以使用类和对象来组织代码,也可以使用函数和结构体等来实现面向过程编程。 -
内存模型和内存管理
:C++在内存模型上(类似jvm运行时数据区)和java有所不同,但也比较类似。在内存管理上,Java是通过Jvm自动管理的;而C++在有些场景需要手动管理内存,比如通过new和delete运算符来动态分配和释放内存。 -
强大的指针(无所不在)
:C++提供了指针的概念,允许直接访问和操作内存地址。这使得C++在一些场景下更高效,但也需要谨慎使用,以避免指针错误和内存安全问题。 -
多重继承
:C++支持多重继承,这意味着一个类可以从多个基类派生。而Java只支持单一继承,一个类只能继承自一个父类。这里不分析谁更好,只是提出这种特性,后面的章节再来讨论。 -
运算符重载
:C++允许对运算符进行重载,从而可以自定义类对象之间的运算行为。这在某些情况下可以使代码更简洁和易读。
C++的数据类型
C++提供了基本的数据类型,int
、short
、long
、float
、double
、char
、bool
,这些和java是一样的。此外还提供了signed
有符号整数和unsigned
无符号整数。struct
结构体,指针和引用。
局部变量也支持static和const
在Java中局部变量是不能使用static
修饰的,而C++中的局部变量可以使用 static
。当 static
修饰局部变量时,它仍然处于内存的全局区,这意味着函数执行完毕后也不会被销毁。这对于需要在多次函数调用之间共享数据的情况会有用。也就是说static
修饰的变量,无论是全局变量还是局部变量都是在全局区。
cpp
void func1() {
static int count = 0;
count++;
cout << count << endl;
}
int main() {
func1(); // 输出: 1
func1(); // 输出: 2
func1(); // 输出: 3
return 0;
}
局部变量也能用const修饰,这意味着该变量在函数执行过程中是只读的,而无法被修改。这一点在很多实际业务场景中非常有用,后面的章节会再来解释这一点。
cpp
void func2() {
//不能再被修改
const int value = 10;
}
void func3(const Student &stu) {
//stu 引用变量只读,无法修改
}
signed和unsigned
cpp
// signed修饰符 ,可以表示负数和正数
signed int a = -10;
// unsigned修饰符 ,只能表示非负数
unsigned int b = 20;
此外,还有一种简化的方式表示无符号整数。uint8_t,uint16_t,uint32_t,uint64_t
。
struct结构体
C++中的结构体是继承自C语言的特性,用struct
关键字表示。是一种复合数据类型,用于将不同类型的数据组合在一起。结构体可以包含多个成员变量,每个成员变量可以是不同的数据类型。但是C++中的结构体可以包含成员函数和访问修饰符,从而更接近于类的概念。
C语言中的结构体
cpp
struct Person {
std::string name;
int age;
};
C++中的结构体
cpp
struct Person {
std::string name;
int age;
//支持函数
void display() {
std::cout << name << std::endl;
std::cout << age << std::endl;
}
};
cpp
int main() {
Person p1; //创建结构体对象
p1.name = "John";
p1.age = 25;
p1.display();
return 0;
}
指针
C++中的指针是一种变量,它是指向某个变量的内存地址。通过指针,我们可以直接访问和操作内存中的数据。
指针的简单使用如下,这里不展开细讲,在后面的章节还会讲解,这里有个基础概念就行。
cpp
int main() {
int a =10;
int *ptr; //声明一个指针
ptr = &a; //取地址运算符(&)将变量的地址赋值给指针
*ptr =20; //修改指向的内容
return 0;
}
引用
在C++中,引用是一种别名,它指向了一个已经存在的变量或者对象,通过引用可以直接操作原始变量。
cpp
int main() {
int a = 10;
int &ref = a; //声明引用ref,它是变量a的别名。
return 0;
}
上面是引用的简单使用。引用必须在声明时进行初始化,并且一旦初始化后,它将一直引用同一个变量。 引用的好处很多,特别是作为函数参数和返回值的时候,这里不展开,后面的章节会解释。
引用与指针的区别
- 引用与指针类似,但有一些重要区别。引用必须在声明时进行初始化,并且不能改变引用所指向的变量。
- 引用不需要使用解引用操作符
*
来访问所引用的变量,而是直接使用引用变量名。
C++中的常量
c++中的常量的含义和java是一样的。在c++中提供了2种方式来定义常量。
使用 #define 定义符号常量
使用方式如下,定义了常量PI。
cpp
#define PI 3.14159
#define
是C
语言中的预处理指令,C++ 继承了这个特性。使用 #define
定义常量时,编译器会直接将代码中出现的符号替换为对应的常量值,这会增加代码的可读性和可维护性。
使用const
cpp
const float PI = 3.14;
const常量在使用上和安全上要比#define更好,建议优先使用const。
namespace命名空间
在C++和C语言中是支持面向过程编程的,也就是说我们可以在文件中直接声明全局的变量或者函数,注意,这一点和java不同,java所有变量和函数的定义都要在类中。这就导致了一个问题,可能出现命名冲突, C语言中通常使用不同的命名约定来避免命名冲突。而C++则引入了namespace
命名空间来解决这个问题,而且它允许我们将相关的变量、函数等放在一个namespace
中。
cpp
namespace space1 {
int sum = 10;
}
namespace space2 {
int sum = 10;
}
int main() {
// 访问命名空间中的变量
std::cout << space1::sum << endl;
std::cout << space2::sum << endl;
return 0;
}
注意:访问命名空间中的成员是通过::
作用域操作符来访问的。此外命名空间还可以定义函数,类对象等。
std
是c++中的标准命名空间。c++标准库中的标识符都定义在这里,比如说常用的<iostream>,std::cout,vector
等。在使用的文件当中加上using namespace std;
即可使用。
C++内存分配的2种方式
在C++中,有多种方式来进行内存的分配和释放,其中包括 malloc
和 free
函数以及 new
和 delete
运算符。 malloc
和 free
是C语言中的函数,用于动态分配和释放内存。C++中继承了这一特性,使用 malloc
分配内存时,需要手动指定要分配的字节数,并返回一个指向分配内存的指针。使用 free
释放内存时,需要传入指向要释放的内存的指针。
cpp
//sizeof(int)是int 的大小,
int *ptr = (int *) malloc(sizeof(int));
free(ptr);
malloc/free是C语言就有的特性,c++继承了这一特性。但c++更推荐使用new运算符分配内存。malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会自动调用构造函数和析构函数进行初始化与清理。注意:对于数组的分配和释放,需要使用 new[]
和 delete[]
运算符。
cpp
int* ptr = new int; // 使用new运算符分配内存
delete ptr; // 使用delete运算符释放内存
int* arr = new int[5]; // 使用new[]运算符分配数组内存
delete[] arr; // 使用delete[]运算符释放数组内存
虽然 malloc
和 free
在C++中仍然可用,但为了更好地利用C++的面向对象的特性和资源管理机制,推荐使用 new
和 delete
运算符进行内存的分配和释放。