【面经分享-CPP篇】[建议收藏] C++基础20问-02

作者 : admin 本文共7734个字,预计阅读时间需要20分钟 发布时间: 2024-06-10 共2人阅读

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员

✨ 本系列打算持续跟新c++面试基础

👏 感谢大家的订阅➕ 和 喜欢💗

文章目录

    • 1.题目:解释C++中的深拷贝和浅拷贝。
    • 2.题目:解释C++中的虚基类及其用途。
    • 3.题目:解释C++中的函数重载和函数覆盖的区别。
    • 4.题目:解释C++中的内存对齐及其作用。
    • 5.题目:解释C++中的内存泄漏及其检测方法。
    • 6.题目:解释C++中的虚析构函数及其用途。
    • 7.题目:解释C++中的多重继承及其优缺点。
    • 8.题目:解释C++中的函数模板和类模板。
    • 9.题目:解释C++中的运算符重载及其实现方式。
    • 10.题目:解释C++中的STL迭代器及其类型。
    • 11.题目:解释C++中的STL算法及其用途。
    • 12.题目:解释C++中的STL容器及其类型。
    • 13.题目:解释C++中的STL适配器及其用途。
    • 14.题目:解释C++中的STL函数对象及其用途。
    • 15.题目:解释C++中的STL绑定器及其用途。
    • 16.题目:解释C++中的STL仿函数及其用途。
    • 17.题目:解释C++中的STL谓词及其用途。
    • 18.题目:解释C++中的STL插入迭代器及其用途。
    • 19.题目:解释C++中的STL适配器及其用途。
    • 20.题目:解释C++中的STL函数对象及其用途。
      • 用途:
      • 示例代码:

1.题目:解释C++中的深拷贝和浅拷贝。

考点:C++基础
答案解析

  • 浅拷贝:复制对象时,只复制对象的基本数据类型成员,对于指针成员,只复制指针的地址,不复制指针指向的内容。这样两个对象共享同一块内存。
  • 深拷贝:复制对象时,不仅复制对象的基本数据类型成员,还复制指针指向的内容。这样两个对象拥有独立的内存。
class MyClass {
public:
    int* data;
    MyClass(int value) {
        data = new int(value);
    }
    // 深拷贝构造函数
    MyClass(const MyClass& other) {
        data = new int(*other.data);
    }
    ~MyClass() {
        delete data;
    }
};

2.题目:解释C++中的虚基类及其用途。

考点:继承
答案解析
虚基类用于解决多重继承中的菱形继承问题。通过将共同的基类声明为虚基类,可以确保在派生类中只存在一份基类的成员。

class A {
public:
    void show() {
        std::cout << "A" << std::endl;
    }
};

class B : virtual public A {
};

class C : virtual public A {
};

class D : public B, public C {
};

int main() {
    D d;
    d.show(); // 输出 "A"
    return 0;
}

3.题目:解释C++中的函数重载和函数覆盖的区别。

考点:面向对象编程
答案解析

  • 函数重载:在同一个作用域内,函数名相同但参数列表不同的多个函数。编译器根据参数列表区分不同的函数。
  • 函数覆盖:在派生类中重新定义基类中的虚函数。派生类的函数覆盖基类的虚函数,调用时根据对象的实际类型决定调用哪个函数。
class Base {
public:
    void func(int x) {
        std::cout << "Base func(int)" << std::endl;
    }
    virtual void show() {
        std::cout << "Base show" << std::endl;
    }
};

class Derived : public Base {
public:
    void func(double x) {
        std::cout << "Derived func(double)" << std::endl;
    }
    void show() override {
        std::cout << "Derived show" << std::endl;
    }
};

int main() {
    Derived d;
    d.func(10); // 输出 "Base func(int)"
    d.func(10.0); // 输出 "Derived func(double)"
    d.show(); // 输出 "Derived show"
    return 0;
}

4.题目:解释C++中的内存对齐及其作用。

考点:内存管理
答案解析
内存对齐是指将数据存储在特定的内存地址上,以提高内存访问效率。内存对齐的作用是减少CPU访问内存的次数,提高程序的执行效率。C++中可以使用#pragma pack指令来控制内存对齐。

#include 
#pragma pack(1) // 设置内存对齐为1字节

struct MyStruct {
    char a;
    int b;
};

int main() {
    std::cout << sizeof(MyStruct) << std::endl; // 输出 5
    return 0;
}

5.题目:解释C++中的内存泄漏及其检测方法。

考点:内存管理
答案解析
内存泄漏是指程序在动态分配内存后未能正确释放,导致内存无法被重用。常见的检测方法包括使用工具如Valgrind、AddressSanitizer等,或者在代码中使用智能指针(如std::unique_ptrstd::shared_ptr)来自动管理内存。

6.题目:解释C++中的虚析构函数及其用途。

考点:继承与多态
答案解析
虚析构函数用于在基类中定义析构函数,使得通过基类指针删除派生类对象时能够正确调用派生类的析构函数,避免内存泄漏。

class Base {
public:
    virtual ~Base() {
        std::cout << "Base destructor" << std::endl;
    }
};

class Derived : public Base {
public:
    ~Derived() {
        std::cout << "Derived destructor" << std::endl;
    }
};

int main() {
    Base* b = new Derived();
    delete b; // 输出 "Derived destructor" 和 "Base destructor"
    return 0;
}

7.题目:解释C++中的多重继承及其优缺点。

考点:继承
答案解析

  • 优点:多重继承允许一个类从多个基类继承,从而可以复用多个基类的功能。
  • 缺点:多重继承可能导致二义性问题和菱形继承问题。二义性问题是指当多个基类中有同名成员时,派生类无法确定使用哪个基类的成员。菱形继承问题是指当一个类从两个基类继承,而这两个基类又从同一个基类继承时,会导致基类的成员被继承多次。
class A {
public:
    void show() {
        std::cout << "A" << std::endl;
    }
};

class B : public A {
public:
    void show() {
        std::cout << "B" << std::endl;
    }
};

class C : public A {
public:
    void show() {
        std::cout << "C" << std::endl;
    }
};

class D : public B, public C {
public:
    void show() {
        B::show(); // 解决二义性问题
    }
};

int main() {
    D d;
    d.show(); // 输出 "B"
    return 0;
}

8.题目:解释C++中的函数模板和类模板。

考点:模板编程
答案解析

  • 函数模板:用于定义与类型无关的函数。函数模板允许编写通用的函数,编译器会根据实际参数类型生成相应的函数代码。
  • 类模板:用于定义与类型无关的类。类模板允许编写通用的类,编译器会根据实际参数类型生成相应的类代码。
template <typename T>
T add(T a, T b) {
    return a + b;
}

template <typename T>
class Stack {
private:
    std::vector<T> elems;
public:
    void push(T const& elem) {
        elems.push_back(elem);
    }
    void pop() {
        if (elems.empty()) {
            throw std::out_of_range("Stack::pop(): empty stack");
        }
        elems.pop_back();
    }
    T top() const {
        if (elems.empty()) {
            throw std::out_of_range("Stack::top(): empty stack");
        }
        return elems.back();
    }
};

9.题目:解释C++中的运算符重载及其实现方式。

考点:运算符重载
答案解析
运算符重载允许为用户定义的类型定义新的运算符行为。可以通过成员函数或友元函数来重载运算符。

class Complex {
private:
    double real, imag;
public:
    Complex(double r, double i) : real(r), imag(i) {}
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
    void print() const {
        std::cout << "(" << real << ", " << imag << ")" << std::endl;
    }
};

int main() {
    Complex c1(1.0, 2.0), c2(2.0, 3.0);
    Complex c3 = c1 + c2;
    c3.print(); // 输出 (3.0, 5.0)
    return 0;
}

10.题目:解释C++中的STL迭代器及其类型。

考点:STL
答案解析
STL迭代器是用于遍历容器元素的对象。STL迭代器的类型包括:

  • 输入迭代器:只读,单向遍历。
  • 输出迭代器:只写,单向遍历。
  • 前向迭代器:读写,单向遍历。
  • 双向迭代器:读写,双向遍历。
  • 随机访问迭代器:读写,支持随机访问。
#include 
#include 

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::vector<int>::iterator it;
    for (it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    return 0;
}

11.题目:解释C++中的STL算法及其用途。

考点:STL
答案解析
STL算法是用于操作容器元素的函数。常见的STL算法包括:

  • std::sort:对容器元素进行排序。
  • std::find:在容器中查找指定元素。
  • std::for_each:对容器中的每个元素执行指定操作。
  • std::copy:将容器元素复制到另一个容器中。
#include 
#include 
#include 

int main() {
    std::vector<int> vec = {5, 3, 1, 4, 2};
    std::sort(vec.begin(), vec.end());
    for (int x : vec) {
        std::cout << x << " ";
    }
    return 0;
}

12.题目:解释C++中的STL容器及其类型。

考点:STL
答案解析
STL容器是用于存储和管理数据的类。STL容器的类型包括:

  • 顺序容器:如std::vectorstd::liststd::deque等。
  • 关联容器:如std::setstd::mapstd::multisetstd::multimap等。
  • 无序容器:如std::unordered_setstd::unordered_mapstd::unordered_multisetstd::unordered_multimap等。
#include 
#include 
#include 

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::set<int> s = {5, 4, 3, 2, 1};
    for (int x : vec) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    for (int x : s) {
        std::cout << x << " ";
    }
    return 0;
}

13.题目:解释C++中的STL适配器及其用途。

考点:STL
答案解析
STL适配器是用于改变容器、迭代器或函数对象行为的类。常见的STL适配器包括:

  • 容器适配器:如std::stackstd::queuestd::priority_queue等。
  • 迭代器适配器:如std::reverse_iteratorstd::back_insert_iteratorstd::front_insert_iterator等。
  • 函数适配器:如std::bindstd::function等。
#include 
#include 

int main() {
    std::stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
    while (!s.empty()) {
        std::cout << s.top() << " ";
        s.pop();
    }
    return 0;
}

14.题目:解释C++中的STL函数对象及其用途。

考点:STL
答案解析
STL函数对象是重载了operator()的类或结构体,可以像函数一样调用。函数对象可以携带状态,适用于需要状态的场景。常见的STL函数对象包括std::plusstd::minusstd::multipliesstd::divides等。

#include 
#include 

int main() {
    std::plus<int> add;
    std::cout << add(3, 4) << std::endl; // 输出 7
    return 0;
}

15.题目:解释C++中的STL绑定器及其用途。

考点:STL
答案解析
STL绑定器用于将函数对象的参数绑定到特定值,从而生成新的函数对象。常见的STL绑定器包括std::bind1ststd::bind2ndstd::bind等。

#include 
#include 

int main() {
    auto add_five = std::bind(std::plus<int>(), std::placeholders::_1, 5);
    std::cout << add_five(10) << std::endl; // 输出 15
    return 0;
}

16.题目:解释C++中的STL仿函数及其用途。

考点:STL
答案解析
STL仿函数是重载了operator()的类或结构体,可以像函数一样调用。仿函数可以携带状态,适用于需要状态的场景。常见的STL仿函数包括std::lessstd::greaterstd::equal_to等。

#include 
#include 

int main() {
    std::less<int> less_than;
    std::cout << less_than(3, 4) << std::endl; // 输出 1 (true)
    return 0;
}

17.题目:解释C++中的STL谓词及其用途。

考点:STL
答案解析
STL谓词是返回布尔值的函数对象。根据参数个数,谓词分为一元谓词和二元谓词。常见的STL谓词包括std::lessstd::greaterstd::equal_to等。

#include 
#include 
#include 

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    auto it = std::find_if(vec.begin(), vec.end(), std::bind2nd(std::greater<int>(), 3));
    if (it != vec.end()) {
        std::cout << *it << std::endl; // 输出 4
    }
    return 0;
}

18.题目:解释C++中的STL插入迭代器及其用途。

考点:STL
答案解析
STL插入迭代器用于在容器中插入元素。常见的STL插入迭代器包括std::back_insert_iteratorstd::front_insert_iteratorstd::insert_iterator等。

#include 
#include 
#include 
#include 

int main() {
    std::vector<int> vec1 = {1, 2, 3};
    std::vector<int> vec2 = {4, 5, 6};
    std::copy(vec2.begin(), vec2.end(), std::back_inserter(vec1));
    for (int x : vec1) {
        std::cout << x << " ";
    }
    return 0;
}

19.题目:解释C++中的STL适配器及其用途。

考点:STL
答案解析
STL适配器是用于改变容器、迭代器或函数对象行为的类。常见的STL适配器包括:

  • 容器适配器:如std::stackstd::queuestd::priority_queue等。
  • 迭代器适配器:如std::reverse_iteratorstd::back_insert_iteratorstd::front_insert_iterator等。
  • 函数适配器:如std::bindstd::function等。
#include 
#include 

int main() {
    std::stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
    while (!s.empty()) {
        std::cout << s.top() << " ";
        s.pop();
    }
    return 0;
}

20.题目:解释C++中的STL函数对象及其用途。

考点:STL
答案解析
STL函数对象(也称为仿函数)是重载了operator()的类或结构体,可以像函数一样调用。函数对象可以携带状态,适用于需要状态的场景。常见的STL函数对象包括std::plusstd::minusstd::multipliesstd::divides等。

用途:

  1. 携带状态:函数对象可以保存状态信息,这在需要状态的场景中非常有用。例如,可以创建一个函数对象来计数某个操作的执行次数。
  2. 灵活性:函数对象可以通过构造函数传递参数,从而在调用时使用这些参数。这使得函数对象比普通函数指针更灵活。
  3. 性能优化:由于函数对象是类的实例,编译器可以对其进行内联优化,从而提高性能。
  4. 与STL算法结合使用:STL算法(如std::sortstd::for_each等)通常接受函数对象作为参数,从而实现自定义的操作。

示例代码:

#include 
#include 
#include 
#include 

// 自定义函数对象
class Increment {
public:
    Increment(int n) : num(n) {}
    int operator()(int x) const {
        return x + num;
    }
private:
    int num;
};

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    Increment inc(5);

    // 使用自定义函数对象
    std::transform(vec.begin(), vec.end(), vec.begin(), inc);

    for (int x : vec) {
        std::cout << x << " "; // 输出 "6 7 8 9 10"
    }
    std::cout << std::endl;

    // 使用STL提供的函数对象
    std::plus<int> add;
    std::cout << add(3, 4) << std::endl; // 输出 7

    return 0;
}
本站无任何商业行为
个人在线分享 » 【面经分享-CPP篇】[建议收藏] C++基础20问-02
E-->