static_cast基本用法

static_cast 是 C++ 中四个命名强制类型转换操作符之一。它用于执行各种不同类型之间的转换

1. 使用场景

1.1 基础数据类型的转换

可以将一种基础数据类型转换为另一种基础数据类型。例如,将 double 转换为 int,或将 float 转换为 double 等。

double d = 5.5;
int i = static_cast<int>(d);  // i = 5

1.2 指向派生类的指针或引用转换为指向基类的指针或引用

class Base {};
class Derived : public Base {};
Derived derivedObj;
Base* basePtr = static_cast<Base*>(&derivedObj);

1.3 指向基类的指针或引用转换为指向派生类的指针或引用

但这是不安全的,因为在转换过程中没有运行时检查。如果确实需要运行时检查,应使用 dynamic_cast

Base* basePtr = new Base();
Derived* derivedPtr = static_cast<Derived*>(basePtr); // 不安全!

1.4 在有关联的类型之间进行转换

例如,转换枚举值为整数

enum Color { RED, GREEN, BLUE };
int value = static_cast<int>(GREEN);  // value = 1

static_cast用法

static_cast<int&&> 是一种将类型转换为右值引用

那么什么是左值和右值呢?

左值 (Lvalue):

  • 可以通过名字引用的对象(如变量)
  • 有一个确定的存储位置
  • 可以出现在赋值号的左边
int x = 10;  // x 是左值
x = 20;      // 可以给左值赋值

右值 (Rvalue):

  • 通常是一个临时对象,存储在寄存器或堆栈中,而不是具名变量
  • 不能出现在赋值号的左边
int y = x + 5;  // x + 5 是右值

左值传递

当一个函数接收参数时,左值传递意味着参数可以直接用左值绑定到函数的形参。通常,左值传递通过引用(&实现,避免拷贝

void print(int& value) {
    std::cout << "Left value: " << value << std::endl;
    value = 5;
}

int x = 10;
print(x);  // x 是左值,这里直接传递左值引用
std::cout << "Left value: " << x << std::endl;

这里会先后输出 10 和 5,首先需要知道的一点,在初学C的时候,我们就知道,变量传入函数里面是不能修改赋值的,只有指针会修改赋值

这是因为在传入参数的时候,会出现形参的概念,也就是传承会被赋值一份,至于复制的过程,涉及寄存器、汇编相关知识,这里不展开

只需要知道传进去的值是被复制的,不是原先的变量,这个时候我们使用 & 可以实现左值的绑定,这个时候就不会再复制形参了

意味着我们传入的值一旦修改就是真的修改了,如果你不希望修改,可以写 const int& value ,当然如果没有需求,尽量不使用左值传递


右值引用

右值引用(T&&是 C++11 引入的新特性,用来接收右值参数

与左值引用不同,右值引用可以绑定到右值(临时对象)上,从而实现高效的资源转移(移动语义)

右值引用的主要用途:

支持移动语义:减少拷贝,提高性能

区分左值和右值:编写重载函数,针对右值进行特殊处理

深拷贝是一种完全复制对象内容的方式,特别是当对象内部有动态分配的资源时,需要确保新对象与原对象之间资源相互独立

std::move()函数的使用方法写在单独的一小节,可以先看使用方法再接下来往下看

1. 实现移动语义

右值引用的最重要用途是支持移动语义,避免昂贵的深拷贝

noexcept 该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化

#include <iostream>
#include <vector>

class MyClass {
public:
    std::vector<int> data;

    // 默认构造函数
    MyClass() { std::cout << "Default constructor\n"; }

    // 拷贝构造函数
    MyClass(const MyClass& other) : data(other.data) {
        std::cout << "Copy constructor\n";
    }

    // 移动构造函数
    MyClass(MyClass&& other) noexcept : data(std::move(other.data)) {
        std::cout << "Move constructor\n";
    }

    // 拷贝赋值运算符
    MyClass& operator=(const MyClass& other) {
        std::cout << "Copy assignment\n";
        data = other.data;
        return *this;
    }

    // 移动赋值运算符
    MyClass& operator=(MyClass&& other) noexcept {
        std::cout << "Move assignment\n";
        data = std::move(other.data);
        return *this;
    }
};

int main() {
    MyClass a;
    a.data = {1, 2, 3};
    MyClass b(a);
    MyClass c = std::move(a);  // 调用移动构造函数
    MyClass d;
    d = std::move(c);         // 调用移动赋值运算符
}

2. 重载函数来区分左值和右值

右值引用可以用来重载函数,根据参数是左值还是右值来执行不同的逻辑

#include <iostream>

void process(const std::string& s) {
    std::cout << "Process left-value: " << s << '\n';
}

void process(std::string&& s) {
    std::cout << "Process right-value: " << s << '\n';
}

int main() {
    std::string str = "Hello";

    process(str);            // 调用左值重载
    process(std::move(str)); // 调用右值重载
    process("World");        // 调用右值重载
}

输出:

Process left-value: Hello
Process right-value: Hello
Process right-value: World

3. 实现通用引用

右值引用配合模板可以实现通用引用,用于完美转发

#include <iostream>
#include <utility>

void process(int& x) {
    std::cout << "Left-value reference: " << x << '\n';
}

void process(int&& x) {
    std::cout << "Right-value reference: " << x << '\n';
}

template <typename T>
void forwardToProcess(T&& t) {
    process(std::forward<T>(t));
}

int main() {
    int a = 42;
    forwardToProcess(a);           // 传递左值
    forwardToProcess(42);          // 传递右值
    forwardToProcess(std::move(a));// 强制作为右值传递
}

输出:

Left-value reference: 42
Right-value reference: 42
Right-value reference: 42

4.返回右值引用

右值引用可以作为返回值类型,允许返回局部对象的资源(通过移动语义)

#include <iostream>
#include <vector>

std::vector<int> createVector() {
    std::vector<int> vec = {1, 2, 3};
    return std::move(temp); // 直接移动 temp 的资源
}

int main() {
    std::vector<int> v = createVector(); // 触发移动语义
    for (int x : v) {
        std::cout << x << " ";
    }
}

5. 高效的容器操作

右值引用常用于标准容器(如 std::vector),使插入和删除操作更加高效

示例:使用右值引用避免拷贝

#include <iostream>
#include <vector>

int main() {
    std::vector<std::string> vec;

    std::string str = "Hello";
    vec.push_back(str);            // 拷贝插入
    vec.push_back(std::move(str)); // 移动插入

    for (const auto& s : vec) {
        std::cout << s << " ";
    }
}

输出:

Hello Hello

results matching ""

    No results matching ""