• 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
  • 相关阅读:
    一个爬虫的练习(妹子图)
    安装模块出现的编译问题(解决)
    基于套接字通信的简单练习(FTP)
    Python3 之选课系统
    数据爬取后台(PHP+Python)联合作战
    让pip 使用国内镜像源
    为啥学蛇和python10年后的变化
    模拟登陆百度以及Selenium 的基本用法
    冒泡排序及其效率分析(无聊搞来玩玩)
    LLVM编译器
  • 原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/12342738.html
Copyright © 2020-2023  润新知