C++对C语言的加强

​ C++对C语言的加强

namespace 命名空间
  • 当使用的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。若不引入using namespace std ,需要这样做。std::cout。
  • C++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。
  • C++命名空间的定义: namespace name { … }
  • using namespace NameSpaceA;
  • namespce定义可嵌套。
“实用性“增强
1
2
// C语⾔中的变量都必须在作⽤域开始的位置定义!!
// C++中更强调语⾔的”实⽤性”,所有的变量都可以在需要使⽤时再定义。
1
2
3
4
5
6
7
8
9
10
11
// Go语言中的变量声明
// Go同样支持在需要时定义变量,并且提供了更简洁的短变量声明方式
func example() {
// 可以在任何需要的地方声明变量
x := 10 // 短变量声明

// 使用x之后再声明y
fmt.Println(x)
y := 20
fmt.Println(y)
}
变量检测增强
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
在C语⾔中,重复定义多个同名的全局变量是合法的
在C++中,不允许定义多个同名的全局变量
C语⾔中多个同名的全局变量最终会被链接到全局数据区的同⼀个地址空间上
int g_var;
int g_var = 1;
C++直接拒绝这种⼆义性的做法。
*/

#include<iostream>
int g_var;
int g_var = 1;
int main(int argc, char *argv[])
{
printf("g_var = %d\n", g_var);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
Go语言中不允许重复定义同名的全局变量
Go在编译时就会检测到重复定义并报错
这与C++的行为一致,都拒绝二义性
*/

package main

import "fmt"

var g_var int // 全局变量声明
// var g_var = 1 // 这行会导致编译错误:g_var redeclared

func main() {
g_var = 1
fmt.Printf("g_var = %d\n", g_var)
}
struct 类型增强
1
2
3
4
/*
C语⾔的struct定义了⼀组变量的集合,C编译器并不认为这是⼀种新的类型
C++中的struct是⼀个新类型的定义声明
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
Go语言中的struct是一种类型定义
Go的struct可以定义方法,类似于C++的类
不需要像C语言那样使用typedef
*/

package main

// 定义结构体类型
type Person struct {
name string
age int
}

// 为结构体定义方法
func (p Person) GetInfo() string {
return fmt.Sprintf("Name: %s, Age: %d", p.name, p.age)
}

func main() {
// 直接使用类型名创建实例
p := Person{name: "张三", age: 20}
fmt.Println(p.GetInfo())
}
C++ 中所有变量和函数都必须有类型
1
2
3
4
5
6
7
8
9
10
11
/*
C++中所有的变量和函数都必须有类型
C语⾔中的默认类型在C++中是不合法的

在C语言中
int f( );表示返回值为int,接受任意参数的函数
int f(void);表示返回值为int的无参函数
在C++中
int f( );和int f(void)具有相同的意义,都表示返回值为int的无参函数
C++更加强调类型,任意的程序元素都必须显示指明类型
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
Go语言中所有的变量和函数都必须显式声明类型
Go不支持默认类型,必须明确指定

在Go中:
func f() int - 表示无参数,返回int的函数
func f(x int, y int) int - 表示接受两个int参数,返回int的函数
Go的类型系统非常严格,不允许隐式类型转换
*/

package main

// 无参数函数
func f() int {
return 42
}

// 带参数函数
func add(x int, y int) int {
return x + y
}

// 多返回值函数(Go的特色)
func divide(x, y int) (int, error) {
if y == 0 {
return 0, fmt.Errorf("除数不能为0")
}
return x / y, nil
}
新增bool 类型关键字
1
2
3
4
5
6
7
8
9
10
11
/*
C++中的布尔类型
C++在C语⾔的基本类型系统之上增加了bool
C++中的bool可取的值只有true和false
理论上bool只占⽤⼀个字节,
如果多个bool变量定义在⼀起,可能会各占⼀个bit,这取决于编译器的实现
true代表真值,编译器内部⽤1来表⽰
false代表⾮真值,编译器内部⽤0来表⽰
bool类型只有true(⾮0)和false(0)两个值
C++编译器会在赋值时将⾮0值转换为true,0值转换为false
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
Go语言中的布尔类型
Go有内置的bool类型,只有true和false两个值
bool类型占用1个字节
Go不允许将整数隐式转换为bool类型
Go的bool类型不能参与数值运算
这使得Go的类型系统更加严格和安全
*/

package main

import "fmt"

func main() {
var flag bool = true
var isValid bool = false

// Go中bool类型的使用
if flag {
fmt.Println("flag is true")
}

// Go不允许这样的隐式转换
// var x int = 1
// if x { } // 编译错误:non-bool x (type int) used as if condition

// 必须显式比较
var x int = 1
if x != 0 {
fmt.Println("x is non-zero")
}

fmt.Printf("flag: %t, isValid: %t\n", flag, isValid)
}
三目运算符功能增强
  • C语言返回变量的值 C++语言是返回变量本身

    C语言中的三目运算符返回的是变量值,不能作为左值使用
    C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方

  • 注意:三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用

    (a < b ? 1 : b )= 30;

  • C语言如何支持类似C++的特性呢?

    当左值的条件:要有内存空间;C++编译器帮助程序员取了一个地址

const 增强
const 基础知识

const修饰指针有三种情况

  1. const修饰指针 — 常量指针
  2. const修饰常量 — 指针常量
  3. const即修饰指针,又修饰常量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main() {

int a = 10;
int b = 10;

//const修饰的是指针,指针指向可以改,指针指向的值不可以更改
const int * p1 = &a;
p1 = &b; //正确
//*p1 = 100; 报错

//const修饰的是常量,指针指向不可以改,指针指向的值可以更改
int * const p2 = &a;
//p2 = &b; //错误
*p2 = 100; //正确

//const既修饰指针又修饰常量
const int * const p3 = &a;
//p3 = &b; //错误
//*p3 = 100; //错误

system("pause");
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
Go语言中没有指针常量的概念
Go的指针不支持指针运算,更加安全
Go使用const关键字定义常量,但不能用于指针
Go通过值传递和指针传递来控制是否可修改
*/

package main

import "fmt"

func main() {
a := 10
b := 20

// Go中的指针
var p1 *int = &a
p1 = &b // 可以改变指针指向
*p1 = 100 // 可以修改指针指向的值

// Go中的常量(不能是指针类型)
const c = 10
// const不能用于指针类型

// 通过函数参数控制是否可修改
modifyValue(&a)
fmt.Println("a =", a) // a被修改

readValue(a)
fmt.Println("a =", a) // a不变
}

// 指针参数:可以修改原值
func modifyValue(p *int) {
*p = 200
}

// 值参数:不能修改原值
func readValue(v int) {
v = 300 // 只修改副本
}

技巧:看const右侧紧跟着的是指针还是常量, 是指针就是常量指针,是常量就是指针常量

合理的利用const的好处,

  1. 指针做函数参数,可以有效的提高代码可读性,减少bug;
  2. 清楚的分清参数的输入和输出特性
const 和 #define

C++中的const修饰的,是一个真正的常量,而不是C中变量(只读)。在const修饰的常量编译期间,就已经确定下来了

C++中的const常量类似于宏定义

const int c = 5; ≈ #define c 5

C++中的const常量与宏定义不同

  • const常量是由编译器处理的,提供类型检查和作用域检查
  • 宏定义由预处理器处理,单纯的文本替换
  • C语言中的const变量

    C语言中const变量是只读变量,有自己的存储空间

  • C++中的const常量可能分配存储空间,也可能不分配存储空间

    当const常量为全局,并且需要在其它文件中使用,会分配存储空间
    当使用&操作符,取const常量的地址时,会分配存储空间
    当const int &a = 10; const修饰引用时,也会分配存储空间

真正的枚举

c 语言中枚举本质就是整型,枚举变量可以用任意整型赋值。而 c++中枚举变量, 只能用被枚举出来的元素初始化。

1
2
3
4
5
6
7
8
9
10
11
#include<iostream>
using namespace std;
enum season{SPR,SUM,AUT,WIN};
int main()
{
enum season s = SPR;
//s = 0; // error, 但是C语⾔可以通过
s = SUM;
cout<< "s = " << s <<endl; //1
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
Go语言中使用const和iota来实现枚举
Go没有enum关键字,但可以通过const常量组实现类似功能
iota是Go的枚举常量生成器,从0开始自增
Go的类型系统确保了类型安全
*/

package main

import "fmt"

// 定义枚举类型
type Season int

// 使用const和iota定义枚举值
const (
SPR Season = iota // 0
SUM // 1
AUT // 2
WIN // 3
)

// 为枚举类型定义String方法,便于打印
func (s Season) String() string {
names := []string{"Spring", "Summer", "Autumn", "Winter"}
if s < SPR || s > WIN {
return "Unknown"
}
return names[s]
}

func main() {
var s Season = SPR
// s = 0 // 可以编译,但不推荐,Go允许将整数赋值给自定义类型
s = SUM
fmt.Printf("s = %d (%s)\n", s, s) // 输出: s = 1 (Summer)

// 更类型安全的做法
s = AUT
fmt.Println("s =", s) // 输出: s = Autumn
}
-------------本文结束 感谢阅读-------------
0%