Interview_C++_day14

i++ 和 ++i 的区别

++i 返回对象的引用,i++ 必须产生一个临时对象保存更改前对象的值并返回,所以导致在大对象的时候产生的比较大的复制开销,效率较低。

// ++i
int& int::operator++() {
	*this += 1;
	return *this;
}
// i++
const int int::operator++(int) {
	int old_value = *this;
	++(*this);
	return old_value;
}

拷贝构造函数

Node a;
Node b(a);
Node c = a;

这里的 (b)(c) 都是一开始是不存在的,是通过 (a) 对象来构造和初始化的。

拷贝构造函数重载形式:

Node (const Node &other) {	

}

如果用户没有自定义拷贝构造函数并且用到了拷贝构造函数,则编译器会生成默认的拷贝构造函数。

(C)++ 中,这三种情况下拷贝构造函数会被使用:

  1. 一个对象以值传递的形式传入函数内。
  2. 一个对象以值传递的形式从函数返回。
  3. 一个对象通过另一个对象初始化。

优点:可以很容易的复制对象。

缺点:对象的隐式拷贝是 (C)++ 中是错误和性能问题的来源之一。它也降低了代码的可读性,并使得对象子程序中的传递和改变变得难以跟踪。

赋值函数

Node a;
Node b;
b = a;

这里的 (b) 已经存在的,在通过 (a) 赋值给 (b)

赋值函数重载形式:

Node& operator=(const Node &other) {

}

拷贝构造函数和赋值函数区别

  1. 拷贝构造函数是在对象初始化时,分配一块空间并初始化,而赋值函数是对已经分配空间的对象进行赋值操作。
  2. 实现上,拷贝构造函数是构造函数,通过参数的对象初始化产生一个对象。赋值函数则是把一个对象赋值给另一个对象,需要先判断两个对象是否是同一个对象,若是则什么都不做,直接返回,若不是则需要先释放原对象内存,在赋值。(可以参考 (shared\_ptr)实现)

总结:

  • 对象不存在,没有通过别的对象来初始化,就是构造函数。
  • 对象不存在,通过别的对象来初始化,就是拷贝构造函数。
  • 对象存在,通过别的对象来初始化,就是赋值函数。

虚函数和内联函数

内联函数通常就是将它在调用处 "内敛的" 展开,消除反复调用的额外开销,但是如果函数太长,会使代码臃肿,反而降低效率。

虚函数可以是内联函数,无论是显式还是隐式,(inline) 都只是一个申请,最终由编译器决定是否内联。所以可以用 (inline) 修饰虚函数,但虚函数表现多态性时,不可以内联,只有当知道调用哪个类的函数时,才可以是内联。

空类的大小

(C)++ 中规定类的大小不为 (0),空类大小为 (1),当类不包含虚函数和非静态成员时,其对象大小也为 (1)。若存在虚函数,则需要存储一个虚函数指针大小,在 (32) 位上为 (4) 字节。

结构体字节对齐

class A {
};
class B{
public:
	A x;
};
sizeof(B)  = 1

class B{
public:
	inline virtual fun() {
	}
};
sizeof(B)  = 4

class B{
public:
	A x;
	inline virtual fun() {
	}
};
sizeof(B)  = 8

可以发现最后一个的 (sizeof) 并不是单纯的 (1+4=5),而直接变成了 (8),因为存在结构体的字节对齐规则。

结构体字节对齐的根本原因: (1)) 移植性更好,某些平台只能在特定的地址访问特定的数据。(2)) 提高存取数据的速度,(CPU) 通常按块读取数据会更加快速。

结构体字节对齐原则:

  1. #pragma pack
    1. 结构内部各成员首地址必然是 (自身大小) 的整数倍。
    2. (sizeof) 最终结果必然是 (结构内部最大成员) 的整数倍,不够补齐
  2. #pragma pack(n)
    1. 结构内部各成员首地址必然是 (min(n, 自身大小)) 的整数倍。
    2. (sizeof) 最终结果必然是 (min(n, 结构内部最大成员)) 的整数倍,不够补齐。
#include<bits/stdc++.h>
using namespace std;

class A {
	char a;
	int b;
	short c;
};
class B {
    int a;
    char b;
    short c;
};

int main() {
    cout << sizeof(A) << endl;	// 12
    cout << sizeof(B) << endl;	// 8
    return 0;
}

造成不同结果的原理在于:

  • 对于 (class A) 来说,内部字节为
a b c
1*** 1111 11**
  • 对于 (class B) 来说,内部字节为
a b c
1111 1* 11
原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/12342738.html