当前位置: 首页 > news >正文

定制型网站建设多少钱电子商务网站建设的规划书

定制型网站建设多少钱,电子商务网站建设的规划书,淘宝客做网站推广,小型IT网站开发公司文章目录 前言#x1f3b1;四、多态的原理#x1f52e;4.1 虚函数表#xff08;vtable#xff09;#x1f52e;4.2 派生类对象中的虚函数表4.2.1 编写程序去访问虚函数表4.2.2 虚表存储位置的验证 #x1f3b1;五、 多态的静态绑定和动态绑定#x1f52e;5.1 静态绑定四、多态的原理4.1 虚函数表vtable4.2 派生类对象中的虚函数表4.2.1 编写程序去访问虚函数表4.2.2 虚表存储位置的验证 五、 多态的静态绑定和动态绑定5.1 静态绑定Static Binding5.1.1 典型场景 5.2 动态绑定Dynamic Binding5.2.1 典型场景5.2.2 C 中静态绑定与动态绑定的区别总结5.2.3 延伸到汇编底层的解释5.2.4 汇编中动态绑定的例子 总结 六、多态的常见面试题 结语 前言 继上篇解锁C多态的魔力灵活与高效的编码艺术上 多态性是面向对象编程的重要特性之一而C通过虚函数、继承等机制实现了这一强大的功能。多态性使得代码更加灵活和可扩展允许不同类型的对象以统一的方式进行操作。在本篇文章中我们将深入探讨C中多态的实现原理、使用场景及其优劣势并通过具体代码示例展示如何利用多态来提升代码的可维护性和复用性。 四、多态的原理 C 中的 多态性运行时多态的底层实现依赖于 虚函数表vtable 和 虚指针vptr。要理解 C 中多态的底层原理需要深入了解虚函数是如何通过这两者来实现的。下面是详细的解释。 4.1 虚函数表vtable 笔试题sizeof(Base)是多少 class Base { public:virtual void func1(){cout func1() endl;} private:int b 1; };int main() {cout sizeof(Base) endl;return 0; }通过上面的打印结果和调试我们发现一个 Base 对象是 8 bytes除了 b 成员还多了一个 _vfptr 放在对象成员变量的前面。_vfptr 本质上是一个指针这个指针我们叫做虚函数表指针一个含有虚函数的类中都至少有一个虚函数表指针因为虚函数的地址要被放到虚函数表中虚函数本质上是存在代码段的虚函数表也简称虚表。 4.2 派生类对象中的虚函数表 上面我们看了一个普通类对象中的虚表下面我们再来看看派生类中的虚表又是怎样的。 // 针对上面的代码我们做出以下改造 // 1.我们增加一个派生类Derive去继承Base // 2.Derive中重写Func1 // 3.Base再增加一个虚函数Func2和一个普通函数Func3 class Base { public:virtual void fun1() { cout Base::fun1() endl; }virtual void fun2() { cout Base::fun2() endl; }void fun3() { cout Base::fun3() endl; } private:int _b 1; };class Derive : public Base { public:void fun1() {} private:int _d 2; };int main() {Base b;Derive d;return 0; }通过监视窗口我们发现了以下几个问题 派生类对象 d 中也有一个虚表这个虚表是作为基类成员的一部分被继承下来的。总的来说d 对象由两部分构成一部分是父类继承下来的成员d 对象中虚表指针就是就是这部分成员中的一个。另一部分则是自己的成员。 基类 b 对象和派生类 d 对象的虚表是不一样的上面的代码中 func1 完成了重写所以 d 的虚表中存的是重写后的 Derive::func1所以虚函数的重写也叫做覆盖覆盖就是指虚表中虚函数的覆盖。重写是语法层面的叫法覆盖是原理层面的叫法。 另外 func2 继承下来后是虚函数所以放进了虚表func3 也继承下来了但是不是虚函数所以不会放进虚表。 虚函数表本质上是一个存虚函数地址的函数指针数组一般情况下这个数组最后面放了一个 nullptr。 总结一下派生类虚表的生成 先将基类中的虚表内容拷贝一份到派生类虚表中。 如果派生类重写了基类中某个虚函数用派生类自己的虚函数覆盖虚表中基类的虚函数。 派生类自己新增的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。在 VS 监视窗口显示的虚表中是看不见的下面将通过程序带大家来验证 这里还有一个比较容易混淆的问题虚函数存在哪虚表存在哪很多小伙伴会觉得虚函数存在虚表虚表存在对象中注意这种回答是错的。这里再次强调虚表存的是虚函数的地址不是虚函数虚函数和普通的成员函数一样都是存在代码段的只是它的地址又存到了虚表中。另外对象中存的不是虚表存的是虚表的地址。那虚表是存在哪儿呢通过验证在 VS 下虚表是存在代码段的。Linux g 下大家可以自己去验证。同一个程序中同一类型的对象共用一个虚表。 4.2.1 编写程序去访问虚函数表 上面提到派生类自己新增的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。但是在 VS 的监视窗口中是看不到以下面的代码为例 class Person { public:virtual void func1() const { cout virtual void Person::fun1() endl; }virtual void func2() const { cout virtual void Person::fun2() endl; }virtual void func3() const { cout virtual void Person::fun3() endl; }//protected:int _a 1; };class Student : public Person { public:virtual void func1() const { cout virtual void Student::fun1() endl; }virtual void func3() const { cout virtual void Student::fun3() endl; }virtual void func4() const { cout virtual void Student::fun4() endl; }//protected:int _b 2; };int main(){Person Mike;Student Jack;return 0; }监视窗口中展现的派生类对象的虚函数表中并没有派生类自己的虚函数 func4。但是我们从内存窗口可以看到第四个地址我们可以大胆的猜测这个就是派生类自己的虚函数 func4 的地址但是口说无凭下面我们来写一段代码验证一下我们的猜想。 typedef void (*FUNC_PTR)(); //定义了一个名为 FUNC_PTR 的类型它是一个指向返回类型为 void 的函数的指针类型。typedef 用于给复杂类型定义一个别名在这里FUNC_PTR 表示一个指向无参数且返回 void 的函数的指针。void PrintVFT(FUNC_PTR* table){for (int i 0; table[i] ! nullptr; i) {// 使用 printf 输出当前虚函数表中第 i 个函数指针的地址。printf([%d]:%p-, i, table[i]); // 将 table[i] 的值即第 i 个函数指针赋值给 ff 是一个函数指针可以像调用普通函数一样调用它。FUNC_PTR f table[i]; f();}printf(\n); }int main() {Person ps;Student st;// 取前四个字节int vft1 *(int*)ps; // 获取 ps 的虚表指针。int vft2 *(int*)st; // 获取 st 的虚表指针。// 将 vft1/vft2 强制转换为 VFPTR*函数指针数组的类型然后传递给 PrintVfptr 函数。// PrintVfptr 函数会输出对象的虚表中每个函数指针的地址并调用这些函数。PrintVFT((FUNC_PTR*)vft1);PrintVFT((FUNC_PTR*)vft2);return 0; }通过上图可以看出我们程序打印出来的地址和监视窗口中显示的地址是一样的并且成功的调用了派生类中的虚函数 func4上图显示的结果完美的验证了我们的猜想。这里也说明了一个问题VS 的监视窗口是存在 Bug 的以后我们在调试代码过程中也不能完全相信监视窗口展现给我们的内容比起监视窗口我们更应该相信内存窗口展现给我们的内容。这里也侧面反映了一个问题只要我们能拿到函数的地址就能去调用该函数正常情况下我们只能通过派生类对象去调用虚函数 func4这里我们直接拿到了这个函数的地址去调用这里的问题在于函数的隐藏形参 this 指针接收不到实参因为不是派生类对象去调用该函数。函数中如果去访问了成员变量那么我们这种调用方式就会出问题。 4.2.2 虚表存储位置的验证 class Person{ public:virtual void func1() const { cout virtual void Person::fun1() endl; }//protected:int _a 1; };class Student : public Person{ public:virtual void func1() const { cout virtual void Student::fun1() endl; }//protected:int _b 2; };int main(){Person Mike;Student Jack;// 栈区int a 10;printf(栈区:%p\n, a);// 堆区int* pa new int(9);printf(堆区:%p\n, pa);// 常量区代码段const char* c hello world!;printf(常量区代码段:%p\n, c);// 静态区数据段static int b 8;printf(静态区数据段:%p\n, b);// 虚表printf(基类的虚表:%p\n, (void*)*(int*)Mike);printf(派生类的虚表:%p\n, (void*)*(int*)Jack);}*(int*)Mike通过将 Mike 对象的地址强制转换为 int* 类型并解引用该指针获得 Mike 的虚表指针vptr。 (void*) 是为了将这个指针转换为 void* 类型以便 printf 正确输出它的地址。 上面取虚表地址是通过强制类型转化来实现的通过上面的监视窗口我们可以看出虚表的地址永远是存储在对象的前四个字节所以这里我们先取到对象的地址然后将其强转为 int* 类型为什么要强转为 int* 呢因为一个 int 型的大小就是四个字节而指针的类型决定了该指针能够访问到内存空间的大小一个 int* 的指针就能够访问到四个字节再对 int* 解引用这样就能访问到内存空间中前四个字节的数据这样就能取到虚表的地址啦。通过打印结果我们可以看出虚表的地址和常量区代码段的地址最为接近因此我们可以大胆的猜测虚表就是存储在常量区代码段的。 五、 多态的静态绑定和动态绑定 在 C 中静态绑定Static Binding和动态绑定Dynamic Binding涉及到对象方法的解析即在调用一个对象的方法时程序如何决定使用哪个具体的实现。这两种绑定机制是面向对象编程中多态性的核心概念特别是在类继承和虚函数的场景下。 5.1 静态绑定Static Binding 静态绑定也叫早期绑定Early Binding是在编译时决定函数调用的绑定方式。编译器在编译过程中根据对象的类型和函数的签名直接将调用的目标地址确定下来。因此静态绑定的函数调用在运行时没有额外的性能开销。 5.1.1 典型场景 静态绑定通常出现在没有使用虚函数的场景下即普通的成员函数调用时编译器在编译期就能确定调用的是哪个函数。 #include iostreamclass Animal { public:void speak() {std::cout Animal speaks std::endl;} };class Dog : public Animal { public:void speak() {std::cout Dog barks std::endl;} };int main() {Animal a;Dog d;a.speak(); // 调用的是 Animal 的 speakd.speak(); // 调用的是 Dog 的 speak }在上述代码中a.speak() 和 d.speak() 的调用在编译期已经被静态解析分别调用了 Animal 和 Dog 的 speak() 方法。这就是静态绑定。 特点 编译时决定调用的函数在编译期决定不依赖运行时的信息。性能高静态绑定不需要运行时开销因此执行效率较高。缺少灵活性不能根据实际对象的类型在运行时做出决策。 5.2 动态绑定Dynamic Binding 动态绑定也叫晚期绑定Late Binding是在运行时决定函数调用的绑定方式。这种方式依赖于对象的实际类型而不是变量声明的类型。C 中的动态绑定依赖于虚函数virtual 关键字实现。 5.2.1 典型场景 动态绑定通常在类的继承结构中使用虚函数时出现。编译器生成一个虚函数表vtable对象在运行时根据其实际类型从虚函数表中查找函数的具体实现。 class Animal { public:virtual void speak() {cout Animal speaks endl;} };class Dog : public Animal { public:void speak() override {cout Dog barks endl;} };int main() {Animal* a new Dog();a-speak(); // 调用的是 Dog 的 speakdelete a; }在这个例子中Animal* a new Dog(); 语句中虽然 a 的类型是 Animal*但由于 speak() 是虚函数调用时会根据对象的实际类型Dog从虚函数表中动态地选择 Dog 类的 speak() 方法。 特点 运行时决定调用的函数在运行时根据对象的实际类型决定。支持多态可以实现基类指针或引用指向派生类对象并在运行时调用派生类的函数。有一定性能开销因为需要通过虚函数表查找函数的实际实现动态绑定相对于静态绑定有额外的开销。 5.2.2 C 中静态绑定与动态绑定的区别总结 静态绑定动态绑定绑定发生在编译时绑定发生在运行时不需要虚函数表依赖虚函数表vtable调用的是编译时确定的类型的函数调用的是运行时对象实际类型的函数使用普通成员函数使用虚函数virtual执行效率高没有运行时开销有一定的运行时开销不支持多态支持多态 5.2.3 延伸到汇编底层的解释 在汇编层面静态绑定和动态绑定的区别可以通过函数调用方式来理解 静态绑定编译器在生成机器码时直接将函数的地址放入调用指令中程序执行时直接跳转到这个地址没有额外的查找开销。 汇编代码中函数调用通常是通过直接的 call 指令跳转到固定的内存地址。 动态绑定编译器为每个包含虚函数的类生成一个虚函数表vtable该表中存储了虚函数的地址。在运行时对象通过虚函数表指针查找实际要调用的函数地址然后跳转执行。 汇编代码中虚函数调用通常会先通过一个中间的表指针间接跳转到实际的函数实现。 5.2.4 汇编中动态绑定的例子 静态绑定的汇编实现可能会包含直接调用目标函数地址 call Dog::speak动态绑定的汇编实现需要通过虚表间接调用 mov rax, [rdi] ; 从对象实例中加载虚表地址 call [rax offset] ; 从虚表中取出实际函数的地址并调用这种方式使得动态绑定的函数调用在运行时依赖对象的实际类型而不是编译时的静态类型。 总结 静态绑定发生在编译时依赖于编译时确定的类型执行效率高但缺少灵活性。动态绑定发生在运行时通过虚函数表查找具体的实现支持多态但有一定的运行时开销。 六、多态的常见面试题 ● inline 函数可以是虚函数嘛 答可以不过编译器会忽略 inline 属性这个函数就不再是 inline因为虚函数要放进虚函数表中。 ● 静态成员可以是虚函数嘛 答不能因为静态成员函数没有 this 指针使用“类型::成员函数”的调用方式无法访问虚函数表所以静态成员函数无法放进虚函数表。 ● 构造函数可以是虚函数嘛 答不能因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。 ● 析构函数可以是虚函数嘛什么场景下析构函数是虚函数 答可以并且最好把基类的析构函数定义成虚函数。 ● 对象访问普通函数快还是虚函数更快 答首先如果是普通对象是一样快的。如果是指针对象或者是引用对象则调用的普通函数更快。因为构成多态运行时调用虚函数要到虚函数表中去查找。 ● 虚函数表是在什么阶段生成的存在哪 答虚函数表是在编译阶段就生成的一般情况下存在代码段常量区。 结语 通过对C多态性的深入了解我们可以更好地编写具有高扩展性和灵活性的代码。多态不仅让代码变得更具适应性还能够减少代码重复提高维护效率。在未来的开发中合理运用多态将为我们的项目带来显著的提升。希望本文的讲解能够帮助读者在实践中更好地掌握这一重要概念。 今天的分享到这里就结束啦如果觉得文章还不错的话可以三连支持一下17的主页还有很多有趣的文章欢迎小伙伴们前去点评您的支持就是17前进的动力
http://www.zqtcl.cn/news/462589/

相关文章:

  • 网站开发算法建网站难不难
  • 茂名模板建站定制网站开发 ide
  • 做网站现在用什么语言网站估价
  • wap开头的网站外贸网站建设官网
  • 做网站说什么5.0啥意思wordpress教程视频 下载
  • 业务型网站做seo郑州网站推广优化
  • 400网站建设南昌网站建设方案详细版
  • 网站评论回复如何做中国住建部和城乡建设官网
  • 怎么建设网站南京做南京华美整容网站
  • 有哪些可以做1元夺宝的网站推广网站哪家做的好
  • 网站备案 域名不是自己的成都电子商务网站
  • 网站内容管理系统建设2021年建站赚钱
  • 网站建设交流发言稿找做网站的上什么app
  • 企业如何应用网站的wordpress lensnews
  • 可信的邢台做网站学电商运营需要多少钱
  • 网站中文名称做微商进哪个网站安全
  • 网站前端建设需要学会什么意思wordpress 快递查询 插件
  • 网站建设腾讯云与阿里云做网站上市的公司
  • 视频直播网站app开发网站备案主体是
  • 做的好的微信商城网站建设商务网站
  • 小白用网站建设工具专做奢侈品品牌的网站
  • 安装vs2015网站开发外包公司为什么没人去
  • 网站关键字多少合适唐河微网站开发
  • 临沂网站建站专业公司网站开发 文学
  • 乐清网站建设服务定制企业网站建设
  • 简单公司网站模版百度站长工具抓取诊断
  • 网站建设与管理维护 大学论文铁路建设单位网站
  • 贵州企业展示型网站建设wordpress文章点不开
  • 毕业设计可以做网站吗网页版征信报告查询
  • 企业网站每年的费用钢筋网片每平米重量