云vps怎么搭建网站,工程建设教育网,wordpress页面内菜单,WordPress占资源多#x1f4a2;欢迎来到张胤尘的技术站 #x1f4a5;技术如江河#xff0c;汇聚众志成。代码似星辰#xff0c;照亮行征程。开源精神长#xff0c;传承永不忘。携手共前行#xff0c;未来更辉煌#x1f4a5; 文章目录 C/C | 每日一练 (2)题目参考答案封装继承多态虚函数底… 欢迎来到张胤尘的技术站 技术如江河汇聚众志成。代码似星辰照亮行征程。开源精神长传承永不忘。携手共前行未来更辉煌 文章目录 C/C | 每日一练 (2)题目参考答案封装继承多态虚函数底层实现单继承多继承 注意事项 C/C | 每日一练 (2)
题目
简述 c 面向对象的三大特性。
参考答案
面向对象三大特性封装、继承、多态。
封装
封装指的是将对象的行为和属性结合成为一个类并隐藏对象的内部实现细节仅通过对象的接口即公开的方法与外界交互。
隐藏内部实现细节保护对象的内部状态防止外部直接访问或修改对象的私有成员。提供统一的接口通过公开的方法如构造函数、成员函数等对外提供服务使对象的使用更加安全和方便。
例如
#include iostreamclass Person
{
private:// 私有成员外部无法直接访问std::string name;int age;public:// 提供接口访问私有成员void setName(const std::string newName){name newName;}void setAge(int newAge){age newAge;}void display() const{std::cout name is age years old. std::endl;}
};继承
继承是指一个类派生类或子类可以继承另一个类基类或父类的属性和方法。子类可以扩展或修改父类的功能而无需重新编写相同的代码支持代码重用和扩展。继承可以是单继承或多继承在 c 中支持
继承的主要作用是
代码复用减少重复代码提高开发效率。拓展功能派生类可以在继承基类的基础上添加新的功能或修改现有功能。
#include iostreamclass Animal
{
public:void eat(){std::cout animal eat std::endl;}
};class Dog : public Animal
{
public:void bark(){std::cout dog eat std::endl;}
};多态
多态是指相同的接口在不同的类实例上具有不同的表现形式。多态分为 编译时多态函数重载和运算符重载 运行时多态通过虚函数实现。
运行时多态是面向对象编程中最重要的多态形式它通过虚函数和继承实现。
例如
#include iostreamclass Shape
{
public:// 定义为虚函数virtual void draw() const{std::cout drawing a shape std::endl;}
};class Circle : public Shape
{
public:// 重写基类的虚函数void draw() const override{std::cout drawing a circle std::endl;}
};class Square : public Shape
{
public:// 重写基类的虚函数void draw() const override{std::cout drawing a square std::endl;}
};int main()
{Shape *s1 new Circle();Shape *s2 new Square();s1-draw(); // drawing a circles2-draw(); // drawing a squaredelete s1;delete s2;
}虚函数
在 c 中虚函数是实现运行时多态的关键机制。它允许派生类重写继承自基类的成员函数从而在运行时根据对象的实际类型调用相应的函数实现。
虚函数是在基类中通过关键字 virtual 声明的成员函数。它的作用是让派生类可以覆盖该函数从而实现多态行为。
#include iostreamclass Base {
public:virtual void display() { std::cout Base::display() std::endl;}
}虚函数的主要作用是实现 动态绑定或运行时多态。具体来说
当通过基类指针或引用调用虚函数时程序会根据对象的实际类型派生类类型来调用对应的函数实现。如果没有虚函数调用的将是基类的成员函数而不是派生类的实现这种行为称为静态绑定。
#include iostreamclass Base {
public:virtual void display() {std::cout Base::display() std::endl;}
};class Derived : public Base {
public:// 重写基类的虚函数void display() override {std::cout Derived::display() std::endl;}
};int main() {Base* ptr new Derived();delete ptr;return 0;
}在上述代码中ptr 是基类指针指向子类对象由于 display() 是虚函数程序会调用派生类的 display() 的实现。
底层实现
虚函数的实现依赖于虚表简称 vtable和虚表指针vptr
每个包含虚函数的类都有一个虚表vtable虚表中存储了该类中所有虚函数的地址。每个对象在对象头中会隐式地包含一个虚表指针vptr指向其所属类的虚表。当通过基类指针或引用调用虚函数时程序会通过 vptr 查找虚表然后在虚表中根据函数索引找到正确的函数地址。执行函数调用。
单继承
单继承的动态多态结构图如下所示 多继承
多继承是 c 中的一种继承方式它允许一个子类从多个基类继承属性和行为。这种继承方式可以提供更大的灵活性使得派生类能够组合多个基类的特性。但是多继承也引入了复杂性尤其是在内存布局、虚函数表、构造和析构顺序等方面。多继承的动态多态结构图如下所示
#include iostreamclass Base1
{
public:virtual void display(){std::cout Base1::display() std::endl;}virtual void show(){std::cout Base1::show() std::endl;}virtual ~Base1(){std::cout Base1::~Base1() std::endl;}private:int a;int b;
};class Base2
{
public:virtual void cat(){std::cout Base2::cat() std::endl;}virtual ~Base2(){std::cout Base2::~Base2() std::endl;}private:int c;
};class Derived : public Base1, public Base2
{
public:// 重写基类的虚函数void display() override{std::cout Derived::display() std::endl;}void cat() override{std::cout Derived::cat() std::endl;}~Derived() override {std::cout Derived::~Derived std::endl;}
private:int d;
};int main() {Base1* ptr1 new Derived();Base2* ptr2 new Derived();delete ptr1;delete ptr2;return 0;
}注意事项
虚函数必须是成员函数全局函数或静态成员函数不能声明为虚函数。派生类的覆盖函数必须与基类的虚函数具有相同的签名函数名、参数类型和数量。如果派生类的函数与基类虚函数签名不一致函数名相同参数类型和数量不相同则不会覆盖而是隐藏。纯虚函数在基类中可以将虚函数声明为纯虚函数即在声明时赋值为 0。包含纯虚函数的类称为抽象类不能实例化对象。
class AbstractClass {
public:virtual void func() 0; // 纯虚函数
};析构函数的虚化如果基类有虚函数通常需要将析构函数声明为虚函数以确保通过基类指针删除派生类对象时能够正确调用派生类的析构函数。
class Base {
public:virtual ~Base() { cout Base destructor endl; }
};class Derived : public Base {
public:~Derived() { cout Derived destructor endl; }
};虚函数的实现依赖于虚表和虚表指针因此会带来一定的性能开销每个对象需要存储一个虚表指针通常为 4 字节或 8 字节。动态多态在调用虚函数时需要通过虚表查找函数地址这比直接调用非虚函数稍慢。但是这种开销通常是可以接受的特别是在需要多态的场景中。
撒花
如果本文对你有帮助就点关注或者留个 如果您有任何技术问题或者需要更多其他的内容请随时向我提问。