Inheritance

Slice off

When doing the up-casting, 向上造型的时候,我们学过可以用Base 的 Pointer 来指向 Derived Class
但是如果直接使用赋值操作,将Derived的对象赋值给Base对象的变量,这个时候会发生截断,比较特殊的是,虚函数表是会被从 Derived copy过去,还是会被直接忽略掉?
事实是:
不会被copy过去, vpointer的虚函数指针会被直接忽略 所以上面赋值后 会使用 Base 的 vtable
notion image
  • 对于动态绑定,除了用一个Up cast的指针去接,也可以使用一个Upcast的引用变量去接
  • 多态体系(里面有虚函数/尤其是纯虚函数): 基类的Destructor就必须做成virtual
如果没有做成 virtual 的析构函数,那么在析构的时候,会优先调用Base类的析构函数,这样可能造成部分变量没有释放; 但如果做成 virtual 的,那么则会优先调用Derived类的析构函数,可以精准地进行内存释放

纯虚接口构造

notion image
没有任何数据的纯虚类

学以致用——Design

Newton Convergence Method

  • 封装一样的东西
  • 抽象出接口
  • Coupling 耦合性
  • Cohesion 内聚性 (一个函数只干一个事,职责是明确的 /对类也是一样)
高内聚低耦合

Copy Constructor 拷贝构造函数

  • 当需要拷贝物体的时候
  • 函数参数传递的时候,就会发生拷贝的行为,例如:
    • notion image
拷贝的行为就需要拷贝构造函数
  • 用一个类本身作为参数,去构造另一个类——拷贝构造
  • 当你不写拷贝构造函数,但是又有拷贝构造发生的时候,程序会自动为你生成一个拷贝构造函数 它的签名 T::T(const T&)
  • 当你的对象Class是一个嵌套的对象,比如你的属性里面有其他对象如vector,则其中每个对象也会发生对应的拷贝,也就会调用每个成员的对应的拷贝构造函数,你可以理解为一个递归的过程——一般不会手动再写拷贝构造,因为编译器自动生成的那个已经十分智能了,尤其是面对用户自定义的对象
notion image
notion image
__m512d _mm512_fmadd_pd (__m512d a, __m512d b, __m512d c)
  • vector 的容量扩容方式是双倍预扩容(可以用均摊分析)

如果在程序中,MyClass bMyClass a 一样,已经提前构造,那么在代码中就不需要再调用拷贝构造函数来初始化 b,而是需要一个赋值操作来将 a 或函数返回的结果赋值给已经构造好的对象 b

关键区别:拷贝构造 vs 赋值操作

  • 拷贝构造函数:当对象在初始化时使用另一个对象来创建时调用,比如:
    • 赋值运算符(operator=):当一个已经构造好的对象被赋值另一个对象时调用,比如:

      修改后的代码:提前构造 b


      输出分析

      解释:

      1. 提前构造 b
          • main 中,MyClass b(20) 调用了构造函数创建对象 b
      1. 调用赋值运算符
          • b = processValue(a); 调用了赋值运算符(operator=),因为 b 已经存在。
      1. 拷贝构造
          • 由于 processValue 按值传递和返回值,依然可能会调用拷贝构造函数。

      重点总结

      如果 b 已经提前构造好,MyClass b = processValue(a); 会变成:
      这时调用的是赋值运算符而不是拷贝构造函数。这两者的区别是: - 拷贝构造函数用于初始化一个新对象。 - 赋值运算符用于将值赋给已经存在的对象。

      补充:启用返回值优化(RVO)时的行为

      现代编译器会对函数返回值启用返回值优化(RVO),这可能会省略返回值的拷贝构造,使得返回的对象直接构造到目标位置 b,从而进一步提升性能。具体行为取决于编译器和编译优化选项。
      例如,启用 RVO 后的优化行为:
      通过返回值优化,构造和析构的次数会进一步减少,提高了效率。
      Loading...