Inheritance
Slice off
When doing the up-casting, 向上造型的时候,我们学过可以用Base 的 Pointer 来指向 Derived Class
但是如果直接使用赋值操作,将Derived的对象赋值给Base对象的变量,这个时候会发生截断,比较特殊的是,虚函数表是会被从
Derived
copy过去,还是会被直接忽略掉?
事实是:
不会被copy过去, vpointer的虚函数指针会被直接忽略
所以上面赋值后 会使用 Base 的 vtable
- 对于动态绑定,除了用一个Up cast的指针去接,也可以使用一个Upcast的引用变量去接
- 多态体系(里面有虚函数/尤其是纯虚函数): 基类的Destructor就必须做成virtual
如果没有做成 virtual 的析构函数,那么在析构的时候,会优先调用Base类的析构函数,这样可能造成部分变量没有释放; 但如果做成 virtual 的,那么则会优先调用Derived类的析构函数,可以精准地进行内存释放
纯虚接口构造
没有任何数据的纯虚类
学以致用——Design
Newton Convergence Method
- 封装一样的东西
- 抽象出接口
- Coupling 耦合性
- Cohesion 内聚性 (一个函数只干一个事,职责是明确的 /对类也是一样)
高内聚低耦合
Copy Constructor 拷贝构造函数
- 当需要拷贝物体的时候
- 函数参数传递的时候,就会发生拷贝的行为,例如:
拷贝的行为就需要拷贝构造函数
- 用一个类本身作为参数,去构造另一个类——拷贝构造
- 当你不写拷贝构造函数,但是又有拷贝构造发生的时候,程序会自动为你生成一个拷贝构造函数 它的签名
T::T(const T&)
- 当你的对象Class是一个嵌套的对象,比如你的属性里面有其他对象如vector,则其中每个对象也会发生对应的拷贝,也就会调用每个成员的对应的拷贝构造函数,你可以理解为一个递归的过程——一般不会手动再写拷贝构造,因为编译器自动生成的那个已经十分智能了,尤其是面对用户自定义的对象
__m512d _mm512_fmadd_pd (__m512d a, __m512d b, __m512d c)
- vector 的容量扩容方式是双倍预扩容(可以用均摊分析)
如果在程序中,
MyClass b
和 MyClass a
一样,已经提前构造,那么在代码中就不需要再调用拷贝构造函数来初始化 b
,而是需要一个赋值操作来将 a
或函数返回的结果赋值给已经构造好的对象 b
。关键区别:拷贝构造 vs 赋值操作
- 拷贝构造函数:当对象在初始化时使用另一个对象来创建时调用,比如:
- 赋值运算符(operator=):当一个已经构造好的对象被赋值另一个对象时调用,比如:
修改后的代码:提前构造 b
输出分析
解释:
- 提前构造
b
: - 在
main
中,MyClass b(20)
调用了构造函数创建对象b
。
- 调用赋值运算符:
b = processValue(a);
调用了赋值运算符(operator=
),因为b
已经存在。
- 拷贝构造:
- 由于
processValue
按值传递和返回值,依然可能会调用拷贝构造函数。
重点总结
如果
b
已经提前构造好,MyClass b = processValue(a);
会变成:这时调用的是赋值运算符而不是拷贝构造函数。这两者的区别是:
- 拷贝构造函数用于初始化一个新对象。
- 赋值运算符用于将值赋给已经存在的对象。
补充:启用返回值优化(RVO)时的行为
现代编译器会对函数返回值启用返回值优化(RVO),这可能会省略返回值的拷贝构造,使得返回的对象直接构造到目标位置
b
,从而进一步提升性能。具体行为取决于编译器和编译优化选项。例如,启用 RVO 后的优化行为:
通过返回值优化,构造和析构的次数会进一步减少,提高了效率。