MirrorYuChen
MirrorYuChen
Published on 2025-01-24 / 18 Visits
0
0

C和C++相似语法学习笔记

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.NULLnullptr

​ 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

参考资料


Comment