首页 > 编程语言 >C++继承、多态代码备忘录

C++继承、多态代码备忘录

时间:2024-03-29 15:33:05浏览次数:26  
标签:ABC vtable Derived 多态 C++ 备忘录 bp Foo class

Hello World

#include <iostream>

// Based on 64-bit machines.

// 1. Size of ABC is 16 bytes, 8 bytes for vptr, 1 byte for char a, 7 bytes
// padding.
// 2. The vptr point to the vtable of ABC, the vtable contains the address of
// the virtual functions of ABC: ~ABC(), Interface() and Foo().
// 3. The entry for Interface() in ABC's vtable is effectively a placeholder,
// since Interface() is pure virtual in ABC, it can't directly provide a valid
// function address for this slot, indicating that the derived classes must
// provide an implementation.
// 4. The destrcutor of base class must be virtual, otherwise the derived
// class destructor will not be called when deleting a derived class object
// through a base class pointer.
class ABC {
 public:
  ABC() : a{'z'} {
    std::cout << "Constructing ABC, its size is " << sizeof(ABC)
              << " byte(s).\n";
  }
  virtual ~ABC() { std::cout << "~ABC()" << std::endl; }
  virtual void Interface() = 0;
  virtual void Foo() { std::cout << "Foo() implemented by ABC" << std::endl; }

 public:
  char a;
};

// 1. Size of Derived is also 24 bytes in total, 8 for vptr, 1 for char a
// inherited from ABC, 8 added by Derived's data member double x. Taking into
// amount those members, the raw sum would be 17 bytes.  However, classes and
// structs are commonly aligned to the size of their largest member or the
// platform's word size for efficiency reasons, which in this case aligns
// naturally due to teh presence of the double and the vptr, both being 8 bytes.
// Thus, the char a is padded to 8 bytes.
class Derived : public ABC {
 public:
  Derived() : x{1.2345} {
    std::cout << "Constructing Derived, its size is " << sizeof(Derived)
              << " byte(s).\n";
  }
  ~Derived() override { std::cout << "~Derived()" << std::endl; }
  virtual void Interface() override {
    std::cout << "Interface() implemented by Derived" << std::endl;
  }
  virtual void Foo() override {
    std::cout << "Foo() implemented by Derived" << std::endl;
  }

  void Bar() {
    std::cout << "Bar(), the Derived featured function" << std::endl;
  }

 public:
  // Question: If x is int, how many bytes does Derived occupy?
  // Answer: 16 bytes, 8 for vptr, 1 for char a, 3 padding bytes, 4 for int x.
  // Question: Why the padding 3 bytes for int x, not 7?
  // Answer: The size of int is 4 bytes, so the padding is 3 bytes to make the
  // size of Derived a multiple of 8 bytes.
  double x;
};

int main() {
  Derived d;
  d.Foo();

  // Let's break down the following code.
  // 1. Object creation: The expression new Derived() creates a Derived object
  // in the heap memory. Even though the pointer p is of type ABC*, the object
  // created is of type Derived.
  // 2. Vptr initialization: When a Drived object is created, its constructor
  // initializes the object's vptr to point to Derived's vtable. The vtable
  // contains pointers to Derived's implementations of all virtual funtions.
  // 3. Dynamic dispatch of Foo(): When you call p->Foo(), the vptr in the
  // object(pointed by p) is used to look up the actual function to call via the
  // vtable associated with the object's dynamic type(Derived). Since Derived
  // overrides Foo(), the Foo() implementation in Derived is located in
  // Derived's vtable and gets executed.
  ABC* bp{new Derived()};
  bp->Foo();

  // But do not get mixed up with the code above.
  // Wrong! x is not a member of ABC.
  // The base class ABC has no knowledge of any members that are defined in its
  // derived classess, even though bp actually points to an object of type
  // Derived. This is not polymorphism.
  // std::cout << bp->x << std::endl;
  // To access x, you could downcast bp to a pointer to Derived, like this:
  std::cout << static_cast<Derived*>(bp)->x << std::endl;
  // Alternatively, if you want to ensure the type is correct at runtime, you
  // can use a dynamic cast:
  auto dp{dynamic_cast<Derived*>(bp)};
  if (dp) {
    dp->Bar();
  }

  // ! The polymorphism is implemented by the vptr and vtable mechanism.

  std::cout << bp->a << std::endl;

  return 0;
}

标签:ABC,vtable,Derived,多态,C++,备忘录,bp,Foo,class
From: https://www.cnblogs.com/tianshihao/p/18103947

相关文章

  • c++类,汽车信息
    #include<iostream>#include<string>usingnamespacestd;class Car{private:      string brand;   stringmodel;   stringcolor;public:   voidcar(stringbrand,stringmodel,stringcolor)   //voidcar()括号里要有形参,不......
  • Java中的多态性:面向对象世界的关键特性
    引言:多态性是面向对象编程(OOP)的核心概念之一,它允许方法在不同对象中具有不同的表现形式。在Java中,多态性不仅提高了代码的灵活性和可扩展性,还使得程序设计更加简洁和优雅。本文将详细探讨Java中多态性的工作原理、实现方式以及它的应用场景。多态性的定义:多态性指的是同......
  • Effective C++ 导论
    芝士wa2024.3.29EffectiveC++.pdf“本书的目的在于引导你如何高效使用C++”本书的研究范围:标准的设计策略特殊语言特性的具体细节例如:如何在inheritance(继承)和templates(模板)之间选择?如何在public(公有)和privateinheritance(私有继承)之间选择?如何在member(成员......
  • C++17: 结构化绑定(Structured Bindings)
    遇到有时候写函数需要返回多个值的情况。C++17之前,只能事先定义一个结构体,然后返回这个结构体类型就可以了。但是如果你的这个结构体类型只在这个这里用一次呢。你还要抠脑壳想一个合适的结构体名字,麻烦!std::tupleC++11引入了一个新的类模板叫std::tuple,是一个容器,可以......
  • 《责任链模式(极简c++)》
            本文章属于专栏-概述-《设计模式(极简c++版)》-CSDN博客模式说明方案:责任链模式将请求的发送者和接收者解耦,构成一个链条,并由多个对象对请求进行处理,直到找到合适的处理者为止。优点:实现了请求发送者和接收者的解耦,灵活性高,易于扩展,每个处理者只需关注自......
  • 《代理模式(极简c++)》
            本文章属于专栏-概述-《设计模式(极简c++版)》-CSDN博客模式说明方案:代理模式充当了客户端和实际对象之间的中介,通过引入代理对象来控制对原始对象的访问。优点:通过代理,可以实现对目标对象的控制,提供更多的功能,例如延迟加载、访问控制、日志记录等。缺点......
  • MD5 计算 (下一代加密辅助类, Win32, C++)
    CCNGHelper.h#pragmaonce#include<string>#include<tchar.h>#include<windows.h>#include<bcrypt.h>#ifdef_UNICODEusing_tstring=std::wstring;#elseusing_tstring=std::string;#endif//下一代加密辅助类//客户端:WindowsVista及......
  • c++ string
     字符串是存储在内存的连续字节中的一系列字符。C++处理字符串的方式有两种,一种来自C语言,常被称为C-风格字符串,另一种是基于string类库的字符串处理方式。C风格字符串的处理可以参考 https://www.cnblogs.com/tongye/p/10688941.html ,本文着重介绍string类库的使用。......
  • C++学习笔记——007
    注意,int*pt;中pt是int值的地址并不意味着pt本身的类型是int。例如,在有些平台中,int类型是个2字节值,而地址是个4字节值。 对于指针,需要指出的另一点是,new分配的内存块通常与常规变量声明分配的内存块不同。常规变量的值都存储在被称为栈(stack)的内存区域中,而new从被称为堆(he......
  • C++学习笔记——006
    事实上,任何两个由空白(空格、制表符和换行符)分隔的字符串常量都将自动拼接成一个。因此,下面所有的输出语句都是等效的:cout<<"I'dgivemyrightarmtobe""agreatviolinist.\n";cout<<"I'dgivemyrightarmtobeagreatviolinist.\n";cout<<&qu......