C++基础知识总结-2

一、为什么析构函数必须是虚函数?为什么默认的析构函数不是虚函数?

(1)、将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象时,释放基类指针可以释放掉子类的空间,防止内存泄漏。

(2)、C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。

二、函数指针

1、定义:函数指针就是指向函数的指针变量。

函数指针本身首先是一个指针变量,该指针变量指向一个具体的函数。这正如用指针变量可指向整型变量、字符型、数组一样,这是是指向函数。

C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可以引用其它类型变量一样,在这些概念上是大体一致的。

2、用途:调用函数和做函数的参数,比如回调函数

3、示例:

char *fun(char *p){...}  //函数fun
char *(*pf)(char *p);  //函数指针pf
pf=fun;  //函数指针pf指向函数fun
pf(p);  //通过函数指针pf调用函数fun

三、C++中析构函数的作用

析构函数与构造函数对应,当对象结束其生命周期,如对象所在的函数以及调用完毕是,系统会自动执行析构函数。

析构函数名也应与类名相同,只是在函数名前面加一个取反符~,例如~MainWindows(),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。

如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它不进行任何操作。所有许多简单的类中没有用显示的析构函数。

如果一个类中有指针,且在使用的过程中动态的申请了内存,那么最好在显示析构函数在销毁类之前,释放掉申请的内存空间,避免内存泄漏。

类析构顺序:1、派生类本身的析构函数;2、对象成员的析构函数;3、基类析构函数。

四、静态函数和虚函数的区别

静态函数在编译的时候就已经确定运行时机,虚函数在运行的时候动态绑定。虚函数因为用了虚函数表机制,调用的时候会增加一次内存开销。

五、虚函数和多态

多态的实现主要分为静态多态和动态多态。静态多态主要是重载,在编译的时候就已经确定;动态多态是用虚函数机制实现的,在运行期间动态绑定。举个例子:一个基类指针指向子类对象时,使用基类的指针去调用子类中重写了的基类中的虚函数的时候,会调用子类重写过后的函数,在基类中声明为加了virtual关键字的函数,在子类中重写的时候不需要加virtual也是虚函数。

虚函数的实现:在有虚函数的类中,类的最开始部分是一个虚函数表的指针,这个指针指向于虚函数表,表中存放了虚函数的地址,实际的虚函数在代码段中。当子类继承了基类的时候也会继承其虚函数表,当子类重写父类中的虚函数的时候,会将其继承到的虚函数表的地址替换为重写的函数地址。使用虚函数,会增加访问内存开销,降低效率。

六、++i和i++的区别及其实现

区别:++i先自增1,在返回;i++先返回,再自增1。

实现:

1、++i实现

int& int::operator++()
{
    *this +=1;
    return *this;
}

2、i++实现

const int int::operator++()
{
    int oldValue = *this;
    ++(*this);
    return oldValue;
}

七、如何写一个在main函数执行前先运行的函数

(1)、在gcc中可以使用attribute关键字,声明constructor和destructor

#include<stdio.h>
__atttibute((constructor)) void before_main()
{
    printf("%s\n",__FUNCTION__);
}

__attribute((destructor)) void after_main()
{
    printf("%s\n",__FUNCTION__);
}

int main(int argc,char **argv)
{
    printf("%s\n",__FUNCTION__);
    return 0;
}

(2)、在VC中,不支持attribute关键字,可以使用如下方法:

view plain
#include<stduo.h>
int main(int argc,char **argv)
{
    printf("%s\n",__FUNCTION__);
    return 0;
}
s
int before_main()
{
    printf("%s\n",__FUNCTION__);
    return 0;
}

int after_main()
{
    printf("%s\n",__FUNCTION__);
    return 0;
}

typedef int func();
#pragma data_seg(".CRT$XIU")
static func *before[] = {before_main};

#pragma data_seg(".CRT$XPU")
static func *after[] = {after_main};

#pragma data_seg()

八、C++中常量的定义及常量在内存中的位置

(1)、定义常量在C++中的定义是一个const加上对象类型,常量定义必须初始化。

(2)、对于局部对象,常量存放在栈区;对于全局对象,常量存放在全局/静态存储区;对于字面值常量,常量存放在常量存储区。

九、const修饰成员函数的目的

const修饰的成员函数表明函数调用不会对对象作出任何更改,事实上,如果确认不会对对象做更改,就应该为函数加上const限定,这样无论const对象还是普通对象都可以调用该函数

发布了60 篇原创文章 · 获赞 8 · 访问量 3149

猜你喜欢

转载自blog.csdn.net/Mr_robot_strange/article/details/104699670
今日推荐