C和C++相似语法学习笔记
1.enum和enum class学习笔记
1.1 enum
- 枚举相当于变量全局定义,可以等价于全局define,如
#include <iostream>
enum color {
Red,
Green,
Blue,
};
int main() {
std::cout << "Red: " << Red << std::endl; // 0
std::cout << "Green: " << Green << std::endl; // 1
std::cout << "Blue: " << Blue << std::endl; // 2
return 0;
}
1.2 enum class
- 相当于对于枚举变量添加了一层class作用域,打印时需要获取一下它潜在类型进行转换后进行打印;
#include <iostream>
enum class Color {
Red,
Green,
Blue,
};
int main() {
using color_type = std::underlying_type<Color>::type;
std::cout << "Red: " << static_cast<color_type>(Color::Red) << std::endl; // 0
std::cout << "Green: " << static_cast<color_type>(Color::Green) << std::endl; // 1
std::cout << "Blue: " << static_cast<color_type>(Color::Blue) << std::endl; // 2
return 0;
}
2.using和typedef
2.1 二者之间区别
- typedef 只能用于类型别名;
- using 既可以用于类型别名,又可以用于模板别名;
2.2 可读性using强于typedef
typedef void(*ptr)(int, const std::string&);
using ptr = void(*)(int, const std::string&);
typedef std::string (Foo::*foo_ptr)(const std::string &);
using foo_ptr = std::string (Foo::*)(const std::string &);
2.3 模板别名只能用using
template <typename T>
using Vec = MyVector<T, MyAlloc<T>>;
Vec<int> vec;
3.struct和class
- 在C/C++语言中,使用struct定义结构体,使用时还需要使用struct关键字,而使用typedef struct则不需要:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct A {
int age;
char name[32];
};
typedef struct {
int age;
char name[32];
} B;
int main(int argc, char *argv[]) {
struct A a;
a.age = 10;
strcpy(a.name, "Hello,A!");
printf("age: %i, name: %s.\n", a.age, a.name);
B b;
b.age = 20;
strcpy(b.name, "Hello,B!");
printf("age: %i, name: %s.\n", b.age, b.name);
return 0;
}
- struct是值类型,class是对象类型;
- struct不能被继承,class可以被继承;
- struct默认访问权限为public,class默认访问权限为private;
- struct总有默认构造函数,即使重载默认构造函数任然会保留,这是因为struct的构造汉是是由编译器自动生成的,如果有重载构造函数,必须对struct变量全部初始化;struct用途是描述轻量级对象,如,point,line等,效率比较高;class在没有重载构造函数时,有默认的无参数构造函数,但一旦被重载一些函数时,默认构造函数将被覆盖;
- new方法不同。struct的new就是执行一次构造函数创建一个新实例,再对所有字段进行copy;而class则是在堆上分配一块内存,然后再执行构造函数,struct的内存并不是在new时候分配,而是在定义的时候分配;
4.常量指针和指针常量
- (1) 区分:const在的左边为常量指针,const在的右边为指针常量;
const int *p = &a; // 常量指针 -> 值为常量
int *const p = &a; // 指针常量 -> 地址为常量
- (2) 区别:常量指针不能修改指针指向地址上的值,指针常量不能修改指针指向;
#include <iostream>
int main() {
int a = 20;
int b = 30;
{
const int *ptr = &a;
std::cout << "*ptr: " << *ptr << std::endl; // 20
// *ptr = 2; // error, can't fix the value
ptr = &b; // can fix the address
std::cout << "*ptr: " << *ptr << std::endl; // 30
}
{
int * const ptr = &a;
std::cout << "*ptr: " << *ptr << std::endl; // 20
// ptr = &b; // error, can't fix the address
*ptr = 50;
std::cout << "a: " << a << " *ptr: " << *ptr << std::endl; // 50, 50
}
return 0;
}
5.extern关键字
5.1 C语言中extern关键字
- [1] 动机:一个C语言项目中,需要在多个文件中使用同一个全局变量或函数,那么就需要在这些文件中都声明一遍;
- [2] 用处:用于声明在其他地方定义的一个变量或函数,在当前位置只是声明,告诉编译器在链接阶段去其他地方找;
- [3] 示例:
#include <iostream>
int main() {
extern int num;
std::cout << "num: " << num << std::endl;
return 0;
}
int num = 3;
5.2 C++中extern关键字之extern "C"
- [1] 动机:编译C++和C函数生成符号表不同,在C++出现之前,很多代码为C写的,底层库也是C语言写的,这些C代码在C++中经常被复用;
- [2] 用处:为了支持/兼容/调用原来的C代码和已经写好的C语言库,正确实现C++代码调用其他C语言代码;
- [3] 示例:
// A.h
#pragma once
int Add(int, int);
// A.c
#include "A.h"
int Add(int a, int b) {
return a + b;
}
// B.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
int callAdd(int a, int b);
#ifdef __cplusplus
}
#endif
// B.cc
#include "B.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "A.h"
int callAdd(int a, int b) {
return Add(a, b);
}
#ifdef __cplusplus
}
#endif
// main.cc
#include <iostream>
#include "B.h"
int main() {
std::cout << "callAdd: " << callAdd(3, 5) << std::endl;
return 0;
}
6.指针和引用
- [1] 定义和性质不同:指针是一个变量,存储的是一个地址,引用则是原变量的一个别名,跟原来变量实质上是一个东西;
- [2] 指针可以有多级,引用只能是一级;
- [3] 指针可以在定义时不初始化,引用则必须在定义时初始化;
- [4] 指针可以指向NULL,引用不可以为NULL;
- [5] sizeof运算结果不同;
- [6] 自增运算意义不同——指针是右移一位,引用则是值加一;
- [7] 作为参数传递时意义不同;
- 注意:指针参数传递本质上是值传递,传递的是一个地址值,传递过程实际上是拷贝了一份指针内存地址;引用参数传递过程不进行拷贝操作,存放的也是实参变量地址;
7.NULL
和 nullptr
C++中 NULL
对应字面量0,nullptr
则对应一个指针,当存在函数重载时,如:
#include <iostream>
void func(int a) {
std::cout << "a called" << std::endl;
}
void func(int *b) {
std::cout << "b called." << std::endl;
}
int main(int argc, char *argv[]) {
{
int *a = NULL;
func(a);
}
{
int *b = nullptr;
func(b);
}
return 0;
}
输出结果:
a called
b called.
那么具体看一下 NULL
的定义:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
C++中 NULL
就是0,而在C中 NULL
为 ((void *)0)
,那么C++中为什么不按照C一样来定义呢?原因很简单,主要就是C++中不支持 void*
类型指针隐式转换成其它类型指针:
void *a;
char *b = a; // error