C/C++基础知识复习(46)

1) C++ 中面向对象编程如何实现动态绑定?

动态绑定 (Dynamic Binding),也称为晚绑定 ,是指在程序运行时根据对象的实际类型来决定调用哪个方法,而不是在编译时就确定方法调用。这通常发生在继承 和多态的场景中,是面向对象编程中非常重要的特性。

C++ 实现动态绑定的机制依赖于 虚函数 (virtual)和 基类指针/引用 来引用派生类对象。动态绑定通过虚函数表(vtable)实现,虚函数表是编译器为每个含有虚函数的类生成的一个数据结构,其中包含指向虚函数的指针。

实现动态绑定的步骤:
  1. 在基类中将函数声明为 virtual。
  2. 在派生类中重写该虚函数。
  3. 通过基类的指针或引用调用虚函数(即使对象实际是派生类的类型)。

C++ 编译器根据对象的实际类型来决定调用哪个函数,这个过程在运行时确定,因此称为动态绑定。

示例代码:
cpp 复制代码
#include <iostream> 
using namespace std; 
class Base { public: // 声明虚函数 
virtual void display() { 
cout << "Base class display" << endl; 
} 
virtual ~Base() {} // 虚析构函数,防止对象销毁时内存泄漏 
}; 
class Derived : public Base { 
public: // 重写虚函数 
void display() override { 
cout << "Derived class display" << endl; 
} }; 
int main() { 
Base* basePtr; // 基类指针 
Derived derivedObj; // 派生类对象 
basePtr = &derivedObj; // 动态绑定:运行时决定调用 Derived 的 display 方法 
basePtr->display(); 
// 输出: Derived class display 
return 0; 
}
解释:
  • Base 类中的 display 函数是虚函数,通过 virtual 关键字声明。
  • Derived 类重写了 display 函数。
  • 在 main 函数中,basePtr 是指向基类对象的指针,但它指向一个派生类的对象。通过 basePtr 调用 display 方法时,程序会动态决定调用 Derived 类的 display 方法,而不是基类的 display 方法。

动态绑定是通过虚函数表(vtable)实现的,虚函数表在运行时根据对象的实际类型来查找和调用合适的函数。

2) C++ 如何管理内存?

C++ 的内存管理主要依赖于手动内存管理(通过 new 和 delete)以及栈和堆的概念。与一些自动化内存管理语言(如 Java 或 Python)不同,C++ 不会自动垃圾回收,程序员需要手动分配和释放内存。这给程序员提供了更多控制权,但也需要小心管理内存,避免内存泄漏和悬空指针等问题。

栈内存与堆内存:
  • 栈内存(Stack):用于存储局部变量和函数调用的上下文。栈内存自动管理,随着作用域的结束,栈上的对象会自动销毁。
  • 堆内存(Heap):用于存储动态分配的内存。堆内存由程序员手动管理,需要显式分配和释放。
1. 手动内存管理:new 和 delete

C++ 提供了 new 和 delete 关键字来在堆上分配和释放内存。它们的使用可以创建动态对象或数组。

  • new:分配内存并返回指向该内存的指针。
  • delete :释放通过 new 分配的内存。
  • new\[\]:分配数组内存。
  • delete\[\]:释放数组内存。
示例代码:
cpp 复制代码
#include <iostream> 
using namespace std; 
int main() { 
// 在堆上分配单个整数 
int* ptr = new int(5); 
cout << "Value: " << *ptr << endl;
// 输出: Value: 5 
// 释放内存 delete ptr; 
// 在堆上分配一个整数数组 
int* arr = new int[3]; 
arr[0] = 1; 
arr[1] = 2; 
arr[2] = 3; 
// 输出数组元素 
for (int i = 0; i < 3; ++i) { 
cout << arr[i] << " "; 
// 输出: 1 2 3 
} 
cout << endl; 
// 释放数组内存 
delete[] arr; 
return 0; 
}
2. 内存泄漏和资源管理

内存泄漏是指程序分配了堆内存,但在不再需要时没有正确释放,从而导致内存无法回收。为了避免内存泄漏,程序员必须确保每次使用 new 分配的内存都必须用 delete 或 delete[] 释放。

RAII (资源获取即初始化)是 C++ 推荐的内存管理模式,利用类的构造函数和析构函数来确保资源的自动释放。通过智能指针(std::unique_ptr、std::shared_ptr 等)可以有效管理内存,避免手动调用 delete。

3. 智能指针:自动内存管理

C++11 引入了智能指针(std::unique_ptr、std::shared_ptr 和 std::weak_ptr),这些指针自动管理堆内存,避免了显式调用 delete,从而减少了内存泄漏的风险。

  • std::unique_ptr:唯一拥有权的智能指针,当其生命周期结束时会自动释放内存。
  • std::shared_ptr:共享拥有权的智能指针,引用计数机制决定何时释放内存。
  • std::weak_ptr :解决循环引用问题,指向 shared_ptr 管理的对象,但不增加引用计数。
示例代码(使用 unique_ptr):
cpp 复制代码
#include <iostream> 
#include <memory> 
using namespace std; 
class MyClass { public: MyClass() { 
cout << "MyClass constructed!" << endl; 
} 
~MyClass() { 
cout << "MyClass destructed!" << endl; 
} }; 
int main() { 
// 使用 unique_ptr 自动管理内存 
unique_ptr<MyClass> ptr = make_unique<MyClass>(); // 不需要显式调用 
delete,unique_ptr 会在超出作用域时自动销毁对象 
return 0; 
}

在上面的代码中,unique_ptr 自动管理 MyClass 对象的生命周期,当 ptr 超出作用域时,它所管理的对象会被自动销毁。

总结:

  • 动态绑定 :通过使用 virtual 关键字在基类中声明虚函数,并通过基类指针或引用来调用派生类的重写函数,从而实现动态绑定。
  • 内存管理 :C++ 提供了手动内存管理机制(new 和 delete),通过栈和堆内存管理不同类型的数据。此外,C++11 引入了智能指针(如 std::unique_ptr 和 std::shared_ptr)来自动管理内存,减少内存泄漏的风险。
相关推荐
十二1 小时前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
心祭丫丫2 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
露天赏雪2 小时前
第3篇:Sentinel熔断降级实战:大模型接口抖动时的服务兜底方案
java·开发语言·人工智能·spring boot·spring·servlet·sentinel
D e re k ZH3 小时前
C++ 从零入门(一):基础语法与程序结构
数据结构·c++·算法
yeccheng4 小时前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
联犀4 小时前
纯 Go 的 CAD 开源库 go-cad:直接解析 DWG/DXF,现在也能导出 PDF
开发语言·golang·pdf
zjxtxdy5 小时前
C++面向对象程序开发-类与对象
开发语言·c++
東隅已逝,桑榆非晚6 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
qq_406981037 小时前
c++拷贝构造函数
开发语言·c++
爱喝雪碧的可乐8 小时前
MATLAB
开发语言·算法·matlab