【高德地图一面面经】

文章讨论了C++中的`new`和`malloc`内存分配区别,涉及构造函数/析构函数、类型安全、静态关键字的作用,以及多态、this指针、虚函数和右值引用的原理,展示了C++中内存管理和高级特性的应用。
摘要由CSDN通过智能技术生成

1. new 和 malloc 的区别?

  • 来源:`new` 是 C++ 中的运算符,而 `malloc` 是 C 语言中的库函数;
  • 构造函数和析构函数:`new` 不仅分配内存,还负责调用对象的构造函数,这意味着它会初始化对象。当使用 `delete` 释放内存时,它还会调用对象的析构函数。而 `malloc` 只负责分配内存,并不会初始化对象或调用构造函数和析构函数;
  • 类型安全:`new` 是类型安全的,它会自动计算需要分配的内存大小,无需手动计算。而 `malloc` 需要手动计算并提供所需的内存大小,这可能导致类型安全问题;
  • 返回类型:`new` 分配内存后返回相应类型的指针,无需进行类型转换。而 `malloc` 分配内存后返回 `void*` 类型的指针,需要进行类型转换以匹配所需的数据类型;
  • 内存分配失败:当 `new` 无法分配内存时,它会抛出 `std::bad_alloc` 异常。而 `malloc` 在内存分配失败时返回一个空指针(`NULL` 或 `nullptr`),需要手动检查分配是否成功;
  • 内存释放:`new` 配套使用 `delete` 运算符释放内存,而 `malloc` 配套使用 `free` 函数释放内存。

2. static 关键字的作用?

  • 静态局部变量:在函数内部,使用 `static` 修饰局部变量可以使其在函数调用期间保持其值。静态局部变量在程序执行时仅初始化一次,每次函数调用时,它们不会被重新初始化,而是保留上次调用时的值。这使得静态局部变量在多次调用之间共享数据时非常有用;
  • 静态类成员:在类中,使用 `static` 关键字修饰成员变量或成员函数可以使其与类的所有实例共享。静态成员变量在类的所有实例之间共享一个值,而静态成员函数没有隐式的 `this` 指针,因此不能直接访问非静态成员变量;
  • 静态全局变量和函数:在全局范围内,`static` 修饰符限制了变量或函数的链接范围。静态全局变量或函数仅在定义它们的源文件内可见,而在其他源文件中不可见。这有助于封装和避免命名冲突

3. 多态的实现原理?

  • 通过虚函数和动态绑定来实现;
  • 当通过基类指针或引用调用虚函数时,实际上会根据对象的实际类型来调用适当的函数实现。这种调用的确定是在运行时进行的,被称为动态绑定;
  • C++ 使用虚函数表(V-table)来实现动态绑定。每个拥有虚函数的类都会在内存中创建一个虚函数表,其中保存了指向每个虚函数的指针。当通过指针或引用调用虚函数时,编译器会根据对象的实际类型查找并调用相应的虚函数。这使得在运行时能够根据对象的类型调用正确的函数实现,实现多态性;
  • 每个对象都会包含一个指向其所属类的虚函数表的指针;

4. this指针的工作原理?

  • this指针是一个隐含的指针,它指向当前对象的地址;
  • 通过将对象的地址传递给成员函数,并在函数内部使用this指针来引用对象的成员。这样,即使有多个对象同时调用同一个成员函数,每个对象都可以通过this指针来访问自己的成员变量,实现了成员函数的对象特定性;
  • 静态成员函数没有this指针,因为它们不属于任何对象,而是属于整个类。只有非静态成员函数才有this指针;

5. 虚函数可以定义为static吗?

  • static成员不属于任何类对象或类实例,所以即使给此函数加上virutal也是没有任何意义的。
  • virtual函数一定要通过对象来调用,需要this指针,而静态成员函数没有this指针;

6. 函数对象的概念?

  • 函数对象(Function Object)是一种可调用的对象,它可以像函数一样被调用;
  • 函数对象是一个类或结构体,它重载了函数调用运算符 operator();
  • 函数对象常用于STL算法中,如排序、查找、遍历等函数,可以通过函数对象来指定自定义的比较规则、操作等;
template <typename T>
struct Greater {
    bool operator()(const T& a, const T& b) {
        return a > b;
    }
};

int main() {
    std::vector<int> nums = {5, 2, 7, 1, 9};
    std::vector<double> nums2 = {3.14, 1.23, 2.56, 0.99};

    // 使用函数对象模板进行排序
    std::sort(nums.begin(), nums.end(), Greater<int>());
    std::sort(nums2.begin(), nums2.end(), Greater<double>());

    // 输出排序结果
    for (int num : nums) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    for (double num : nums2) {
        std::cout << num << " ";
    }

    return 0;
}

7. 左值和右值的区别?

  • 左值指的是具有标识符的表达式,它表示一个具体的内存位置。左值可以出现在赋值语句的左边或右边,可以被取地址、修改和访问。例如,变量、数组元素和对象的成员等都是左值。

  • 右值指的是不具有标识符的表达式,它表示一个临时的值或计算结果。右值只能出现在赋值语句的右边,不能被取地址和修改。例如,字面量、临时变量和返回值等都是右值。

  • 左值和右值的区别主要体现在它们的可修改性和生命周期上。左值具有持久性,可以被多次访问和修改,而右值通常是临时的,只能被使用一次。此外,左值可以被取地址,而右值不能。

  • C++11引入了右值引用(rvalue reference)的概念,它可以绑定到右值,并且具有特殊的语义,如移动语义和完美转发。右值引用的引入使得对右值的处理更加高效和灵活。

8. 右值引用的概念?

  • 右值引用的声明语法是在类型名后面加上两个连续的“&”,例如int&&。它可以绑定到右值,但不能绑定到左值;
  • 右值引用的主要目的是实现移动语义(Move Semantics)和完美转发(Perfect Forwarding);
  • 移动语义允许我们将资源(如动态分配的内存)从一个对象转移到另一个对象,而不是进行昂贵的拷贝操作。通过使用右值引用,我们可以在移动构造函数和移动赋值运算符中使用移动语义,提高代码的效率;

9. 移动语义的概念?

  •  通常用于将对象作为右值传递给函数、移动构造函数和移动赋值运算符等场景。通过将对象转换为右值引用,可以告诉编译器可以使用移动语义而不是复制语义来操作对象,提高性能

std::vector<int> source{1, 2, 3};
std::vector<int> dest = std::move(source);  // 将source的内容移动到dest中

10.完美转发的概念?

  • 主要用于解决模板函数中参数传递的值类别问题,可以使用`std::forward`来,根据原始参数的值类别选择性地将参数转发为左值引用或右值引用,实现完美转发。

template<typename Func, typename... Args>
decltype(auto) wrapper(Func&& func, Args&&... args)
{
    // 在这个例子中,我们将参数 args 转发给 func 函数进行处理
    return std::forward<Func>(func)(std::forward<Args>(args)...);
}

void process(int& x)
{
    std::cout << "Lvalue: " << x << std::endl;
}

void process(int&& x)
{
    std::cout << "Rvalue: " << x << std::endl;
}

int main()
{
    int value = 42;
    wrapper(process, value);          // 传递左值
    wrapper(process, 123);            // 传递右值

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨主任o_o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值