前端?C++ ?较大差异基础罗列

文章目录

Basic

1、std::是什么
shell 复制代码
 auto d = std::string("world");
 std::cout << d << " ";

stdstandard(标准) 的缩写,它是 C++ 标准库的 命名空间(namespace) 。如果不想每次都写 std::,可以在文件开头写using namespace std;,之后就可以直接写coutstringvector了。但在大型项目中不推荐这样做,因为不同库可能有同名函数,会产生命名冲突。

2、& (取地址符)和 * 的含义
shell 复制代码
int x = 10;
const int* p = &x;    // p 指向 x,p 记住了 x 的地址

// *p = 20;            // ❌ 不行!const 说"指针指向的内容不能改"
x = 30;                // ✅ 可以,直接改 x 本身没问题
std::cout << *p << "\n"; // 输出 30,因为 p 指向 x,x 已经变成了 30
// &x   → 0x01    (x 的地址)
// p    → 0x01    (p 里存的值,就是 x 的地址)
// *p   → 10      (顺着地址找到里面存的值)
符号 什么时候 含义 口语理解
&x 表达式中 取 x 的地址 "x 住哪儿?"
int* p 声明时 p 是指针 "p 是个专门存地址的变量"
*p 表达式中 取 p 指向的值 "顺着地址看看里面是谁"

其他,注意在遍历的时候,如果想对原数值进行修改一定要遍历读取引用,否则是复制一份的数据修改不了原来数组

shell 复制代码
std::vector<int> scores {12,23,45,123,345};
for(int& score : scores){
	score++;
}
//score原数组中的值
//&score原数组中的值的地址
3、C++中的遍历

使用 :

shell 复制代码
#include <vector>
auto vec = std::vector{1,2,3};

// 写法一:传统 for(和 JS/C/Java 一样)
for (int i = 0; i < vec.size(); i++) {
    std::cout << vec[i] << " ";
}

// 写法二:范围 for(更简洁,推荐)
for (auto x : vec) {
    std::cout << x << " ";
}
4、C++中数组和动态数组vector
shell 复制代码
int vec = std::vector{1,2,3};	//动态数组,自动扩容不固定大小
int arr[] = {1,2,3}	;	//常规数组

数组常用操作

shell 复制代码
auto vec = std::vector{1,2,3};

vec.push_back(4);	//末尾加
vec.size();		//长度计算
vec[0];		//取值
vec.pop_back();		//删除末尾
vec.empty();		//判断是否为空
5、map & set 常用操作
  • map集合
shell 复制代码
std::map<string,int> ages = {{'jack',18},{'eric',12}};	//声明

ages['jack'];	//18
ages['vicky'] = 18;
ages.size();	//3
ages.count('bob');	//false,count是判断是否存在

for(auto [name,age] : ages){
	std::cout << name << "is" << "age" << "\n";
}
  • set不重复几何
shell 复制代码
std::set<int> nums = {1,2,3,4,5};

nums.insert(9);	//插入
nums.erase(2);	//擦除
nums.count(5);	//是否存在
numns.size();	//大小
6、static

static声明的变量只初始化一次,并且在函数调用执行完成之后不会销毁

shell 复制代码
void counter (){
	static int count = 0;
	count++;
	std::cout << count << "\n";
}
int main(){
	counter();	//1
	counter();	//2
	counter();	//3
}
7、nullptr现代空指针

比 NULL 更安全、更清晰,避免类型混淆。

  • NULL 其实是 C 语言的宏,本质就是整数 0
  • nullptr 有自己专属的类型 std::nullptr_t只能赋值给指针,不会被当成整数。nullptr 的类型就是指针。
shell 复制代码
int* p = nullptr;   // 空指针,安全

if (p == nullptr) {  // 判断指针是否为空
    std::cout << "p 是空指针\n";
}

// 也可以简写为:
if (!p) {            // 等价写法
    std::cout << "p 是空指针\n";
}
8、ecplicit禁止隐式转换

ecplicit Distance(double m) : meters(m) {}

shell 复制代码
#include <iostream>

class Distance {
private:
    double meters;
public:
    // explicit Distance(double m) : meters(m) {}   // 加explicit更安全
    Distance(double m) : meters(m) {}               // 不加会隐式转换

    double get() const { return meters; }
};

void print(double d) {
    std::cout << "距离: " << d << " 米\n";
}

int main() {
    Distance d = 500;          // 如果构造函数不是explicit,这里允许
    print(d);                  // 隐式把 Distance → double
    // print(500);             // 如果加了explicit,这行会报错
}
9、构造函数的初始化&调用

这真的,,,前端看到震惊写法(孤陋寡闻了,,,

shell 复制代码
#include <iostream>

class Distance {
private:
    double meters;
public:
    Distance(double m) : meters(m) {}               // 不加会隐式转换
    double get() const { return meters; }
};

int main() {
    Distance d = 500;          // 如果构造函数不是explicit,这里允许
    print(d);                  // 隐式把 Distance → double
    // print(500);             // 如果加了explicit,这行会报错
}
  • 构造函数定义:和类名同名的函数,就是构造函数
  • 写法、功能分析:Distance(double m) : meters(m) {}
shell 复制代码
Distance(double m) : meters(m) {}   //构造函数,功能同下函数体内赋值
Distance(double m) {
	meters = m;
}

//WHY?为什么多此一举这样写?因为有些情况下,函数体内赋值做不到,必须用初始化列表
//如下:
class Example {
    const int id;              // const 成员,必须在创建时就赋值
    const std::string& name;   // 引用成员,必须在创建时就绑定

    // ✅ 初始化列表------创建时直接赋值
    Example(int i, std::string& n) : id(i), name(n) {}

    // ❌ 函数体内赋值------做不到!
    Example(int i, std::string& n) {
        id = i;     // 报错!const 不能赋值
        name = n;   // 报错!引用不能重新绑定
    }
};
  • Distance d = 500 为什么可以?
shell 复制代码
Distance d = 500;	//自动翻译成下面
Distance d = Distance(500);	//同Distance d{500};   
  • 多个变量值怎么初始化构造函数
shell 复制代码
class Box {
    double length, width, height;
public:
    Box(double l, double w, double h) : length(l), width(w), height(h) {}
};

//初始化
// 写法一:直接初始化(最常用)
Box b(1.0, 2.0, 3.0);

// 写法二:列表初始化(C++11,推荐)
Box b{1.0, 2.0, 3.0};

// 写法三:先构造再赋值
Box b = Box(1.0, 2.0, 3.0);

// 写法四:列表初始化 + auto(C++17,最简洁)
auto b = Box{1.0, 2.0, 3.0};
10、const
  • const 跟在函数后面,意思是:"这个函数承诺不修改对象内部的任何数据"

    shell 复制代码
    class Dog : public Animal {
        std::string name = "旺财";
    
        void speak() const {
            // ✅ 可以读数据
            std::cout << name << " 汪汪汪!\n";
    
            // ❌ 不能改数据,编译器会报错
            // name = "小白";
        }
    
        void rename(std::string n) {   // 没有 const
            name = n;   // ✅ 可以改,因为这个函数没承诺"只读"
        }
    };
  • const 对象只能调用 const 函数

    shell 复制代码
    const Dog myDog;         // const 对象
    
    myDog.speak();           // ✅ 可以,speak() 有 const,承诺不改
    myDog.rename("小白");    // ❌ 报错!rename() 没 const,const 对象不能调用
11、virtual虚拟函数和override重写
  • 有了 virtual,编译器会去看实际创建的对象是什么,然后调用对应的函数。
shell 复制代码
class Animal {
public:
    virtual void speak() { std::cout << "某种动物叫声\n"; }
};

class Dog : public Animal {
public:
    void speak() override { std::cout << "汪汪汪!\n"; }
};

Animal* pet = new Dog();
pet->speak();   // 输出:汪汪汪!
                // ✅ 程序运行时发现实际对象是 Dog,调用 Dog 的 speak
  • 其他
问题 答案
为什么叫"虚"函数? 因为调用哪个版本的函数,要等到运行时才确定,"不确定"所以叫"虚"
只有虚函数能重写吗? 是的,只有父类的 virtual 函数才能被子类 override
virtual 的作用? 让编译器在运行时根据实际对象类型调用正确的函数(多态)
override 的作用? 告诉编译器"我要重写父类的虚函数",写错了编译器会报错
12、->. 的区别
  • pet->speak();等同于pet.speak();吗?

取决于 pet指针 还是对象

pet 的类型 调用方式 示例
指针(Animal* pet -> pet->speak();
对象(Animal pet . pet.speak();

并且->是简写

shell 复制代码
pet->speak();
// 等价于
(*pet).speak();
// 意思是:先通过地址找到对象(*pet),再调用方法(.speak())
13、constexpr编译期计算

constexpr = "这个值/计算在编译时就能搞定"。好处是更快、更安全。但不能用于有 I/O、动态内存等运行时才能完成的操作。

shell 复制代码
// ✅ 可以加 constexpr
constexpr int add(int a, int b) {
    return a + b;    // 简单的计算,没问题
}

// ❌ 不能加 constexpr
constexpr void print_hello() {
    std::cout << "hello\n";  // ❌ 有 I/O 操作,编译时做不了
}

// ❌ 不能加 constexpr
constexpr int get_random() {
    return rand();   // ❌ 每次结果不同,编译时确定不了
}
  • 限制
能做的 不能做的
简单的数学计算 std::cout 等 I/O 操作
条件判断 if 调用非 constexpr 的函数
递归(C++14 起) 使用 new(动态内存)
返回常量 修改外部状态
  • constexpr 变量 vs const 变量
const constexpr
含义 运行时不能改 编译时就能确定
何时确定值 可以是运行时 必须编译时
shell 复制代码
const int x = get_input();       // ✅ 运行时才确定,但之后不能改
constexpr int y = get_input();   // ❌ 编译时确定不了,报错!
constexpr int z = 100;           // ✅ 编译时就知道是 100
14、你还不知道using的几种用法吗
  • 用法一:引入命名空间
cpp 复制代码
using namespace std;    // 引入整个 std 命名空间
// 之后可以直接写 cout,不用写 std::cout
  • 用法二:引入命名空间中的某一个成员
cpp 复制代码
using std::cout;        // 只引入 cout,不引入其他的using std::endl;        // 只引入 endl
cout << "hello" << endl;   // ✅ 可以直接用// cin >> x;               // ❌ 不行,没引入 cin

using namespace std; 更安全,因为只引入了你需要的东西,不会产生命名冲突。

  • 用法三:给类型起别名(类型别名)
cpp 复制代码
using StringVec = std::vector<std::string>;
//  新名字↑      =     原来的类型

意思是:以后 StringVec 就等价于 std::vector<std::string>

cpp 复制代码
StringVec v2 {"苹果", "香蕉"};
// 等价于
std::vector<std::string> v2 {"苹果", "香蕉"};
15、enum class(强类型枚举)
shell 复制代码
#include <iostream>

enum class Color { Red, Green, Blue };   // 强类型,不会隐式转int

int main() {
    Color c = Color::Green;

    // if (c == 1) {}          // 错误!不能直接跟int比
    if (c == Color::Green) {
        std::cout << "是绿色\n";
    }

    // 想转int必须显式转换
    std::cout << "底层值: " << static_cast<int>(c) << "\n";
}
相关推荐
C语言小火车3 小时前
C/C++ 为什么需要编译器?
开发语言·c++
旖旎夜光4 小时前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
吞下星星的少年·-·4 小时前
C++ 萌新语法入门篇
c++·算法比赛
霍霍的袁4 小时前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
another heaven5 小时前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
程序猿编码5 小时前
告别改源码适配模型:纯 C++ 可配置 LLM 推理引擎,全格式全结构兼容
c++·大模型·llm·推理引擎
此生决int5 小时前
深入理解C++系列(20)——C++11(下)
开发语言·c++
郝学胜-神的一滴5 小时前
C++20模板元编程 07:吃透名称绑定与编译期递归核心原理
c++·程序人生·vs·模板元
S_WEAN6 小时前
【C++】STL - Vector类的模拟实现
c++