内联函数和宏定义区别,构造函数析构函数虚函数是否可以声明为内联函数,大小端问题,初始化成员列表,变量声明定义区别,final和override关键字,main函数执行之前和执行之后的代码

内联函数和宏定义的区别

内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候,内联函数可以直接嵌入到目标代码中。

内联函数适用场景

  • 使用宏定义的地方都可以使用inline函数。

  • 作为类成员接口函数来读写类的私有成员或者保护成员,会提高效率。

内联函数一般只用于如下情况

  • 一个函数不断被调用
  • 函数只有简单的几行,且函数不包含for,while,switch等语句

为什么不能把所有的函数写成内联函数

内联函数以代码复杂为代价,它省去函数调用的开销来提高执行效率。所以一方面如果内联函数体内代码执行时间相比函数调用开销较大,则没有太大的意义;另一方面每一处内联函数的调用都要复制代码,消耗更多的内存空间。因此以下情况不宜使用内联函数。

  • 函数体内的代码比较长,复制代码时将耗费更多代价
  • 函数体内有循环,函数执行时间要比函数调用的开销大

主要区别

  • 内联函数在编译时展开,宏在预编译时展开
  • 内联函数直接嵌入到目标代码中,宏是简单的做文本替换
  • 内联函数有类型检测,语法判断等功能,而宏没有
  • 内联函数是函数,宏不是,内联函数具有重载等功能
  • 宏定义时要注意书写(参数要括起来)否则容易出现歧义,内联函数不会产生歧义
  • 内联函数代码被放到符号表中,使用时像宏一样展开,没有调用的开销,效率很高
  • 在使用时,宏只做简单字符串的替换(编译前)。而内联函数可以进行参数类型检查(编译时),且具有返回值
  • 内联函数可以作为某个类的成员函数,这样可以使用类的保护成员和私有成员。而当一个表达式涉及到类保护成员或私有成员时,宏就不能实现了。

构造函数,析构函数,虚函数可否声明为内联函数

首先,将这些函数声明为内联函数,在语法上没有错误。

构造函数和析构函数声明为内联函数是没有意义的

《effective c++》中阐述的是:将构造函数和析构函数声明为inline是没有什么意义的,即编译器并不真正对声明为inline的构造和析构函数进行内联操作,因为编译器会在构造和析构函数中添加额外的操作(申请/释放内存,构造/析构对象等),使得构造函数/析构函数并不像看上去的那么精简。其次,class中的函数默认是Inline的,编译器也只是有选择性的inline,将构造函数和析构函数声明为内联函数是没有什么意义的

将虚函数声明为inline,要分情况讨论

如果是用指向派生类的指针(多态性)调用声明为inline的虚函数,不会内联展开,当用对象本身调用虚函数时,会内联展开,当然前提仍然是函数并不复杂的情况下

如何用代码判断大小端存储

大端存储: 字数据的高字节存储在低地址中。

小端存储: 字数据的低字节存储在低地址中。

例如:32bit的数字0x12345678

小端模式中的存储方式为:

内存地址0x40000x40010x40020x4003
存放内容0x780x560x340x12

大端模式中的存储方式为:

内存地址0x40000x40010x40020x4003
存放内容0x120x340x560x78

判断方式

方式1:用union联合体

#include <iostream>
using namespace std;
//union联合体的重叠式存储,联合体占用内存的空间为每个成员字节长度的最大值
union endian
{
    int a;
    char ch;
};
int main()
{
	endian value;
    value.a = 0x1234;
    //a和ch公用4字节的内存空间
    if(value.ch == 0x12)
        cout << "big endian" << endl;
    else if(value.ch == 0x34)
        cout << "little endian" <<endl;
}

方式2:使用强制类型转换

#include <iostream>
using namespace std;
int main()
{
    int a = 0x1234;
    //由于int和char的长度不同,借助int型转换成char型, 只会留下低地址的部分
    char c = (char)(a);
    if(c == 0x12)
        cout << "big endian" << endl;
    else if(c == 0x34)
        cout << "little endian" <<endl;
}

哪几种情况必须用到初始化成员列表?

  • 初始化一个const成员
  • 初始化一个reference成员
  • 调用一个基类的构造函数,而该函数有一组参数
  • 调用一个数据成员对象的构造函数,而该函数有一组参数。

变量声明和变量定义区别

  • 声明仅仅是把变量声明的位置及类型提供给编译器,并不分配内存空间;定义要在定义的地方为其分配存储空间
  • 变量能且只能被定义一次,但是可以被多次声明
extern int i; //声明了i
int j;        //声明并定义了j

任何包含了显式初始化的声明即成为定义,如

extern double pi = 3.14;   //定义

final 和override关键字

override

当在父类中使用了虚函数的时候,你可能需要在某个子类中对这个虚函数进行重写,以下方法都可以:

class A
{
    virtual void foo();
}

class B : public A
{
    void foo(); 
    virtual void foo();
    void foo() override;
}

如果不使用override,当你手一抖,将foo()写成了f00()会怎么样呢?结果是编译器并不会报错,因为它并不知道你的目的是重写虚函数,而是把它当成了新的函数。如果这个虚函数很重要的话,那就会对整个程序不利。所以,override的作用就出来了,它指定了子类的这个虚函数是重写父类的话,如果你名字不小心打错的话,编译器是不会通过的。

class A
{
    virtual void foo();
}
class B : public A
{
    virtual void f00();               //OK,这个函数是B新增的,不是继承的
    virtual void fo0() override;      //Error,加了override之后,这个函数一定是继承A的,
}                                     //A找不到就报错

final

当不希望某个类被继承,或不希望某个虚函数被重写,可以在类名和虚函数后添加final关键字,添加final关键字后被继承或重写,编译器会报错。

例子如下:

class Base
{
	virtual void foo();
};

class A : public Base
{
	void foo() final;    //foo被override并且是最后一个override,在其子类中不可以重写    
};

class B final : A  //指明B是不可以被继承的
{
 	void foo() override;  //Error: 在A中已经被final了   
};

class C : B  //Error: B is final
{
    
};

在main执行之前和之后执行的代码可能是什么?

main函数执行之前

main函数执行之前,主要就是初始化系统相关资源:

  • 设置栈指针
  • 初始化静态static变量和global全局变量,即.data段的内容
  • 将未初始化部分的全局变量赋初值:数值型short,int,long等为0,boolFALSE,指针为NULL等等,即.bss段的内容
  • 全局对象初始化,在main之前调用构造函数,这是可能会执行前的一些代码
  • 将main函数的参数argc,argv等传递给main函数,然后才真正运行main函数

main函数执行之后

  • 全局对象的析构函数会在main函数之后执行
  • 可以用atexit注册一个函数,它会在main之后执行
// C++ program to illusttrate 
// atexit() function 
#include <bits/stdc++.h> 
using namespace std; 
  
// Returns no value, and takes nothing as a parameter 
void done() 
{ 
    cout << "Exiting Successfully"
         << "\n"; // Executed second 
} 
// Driver Code 
int main() 
{ 
    int value; 
    value = atexit(done);   //atexit返回零:表示注册成功
  							//atexit返回非零,表示注册失败
    if (value != 0) { 
        cout << "atexit () function registration failed"; 
        exit(1); 
    } 
    cout << " Registration successful"
         << "\n"; // Executed First 
    return 0; 
}
/*
Registration successful
Exiting Successfully
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值