C++面试准备日记——函数

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

(1)析构函数与构造函数相对应,当对象结束其生命周期时系统会自动执行析构函数,析构函数用来做清理善后的工作,如释放内存空间等;
(2)析构函数名应与类名相同,只是在函数名前加一个位取反符~,以区别构造函数。它不能带任何参数,也没有返回值。只能有一个析构函数,不能重载。
(3)如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数;如果用户自定义了析构函数,编译器也会合成一个析构函数,在执行时会先调用自定义的析构函数再调用合成的析构函数。它也不进行任何操作,所以许多简单的类中没有显式地析构函数。
(4)如果一个类中有指针,且在使用的过程中动态的申请了内存,那么最好显式构造析构函数,在函数销毁之前,释放掉申请的内存空间,避免内存泄漏。

2、类析构顺序

(1)派生类本身的析构函数;
(2)对象成员析构函数
(3)基类析构函数

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

(1)如果父类可能会被继承,那么将析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象时,释放基类指针时可以释放掉子类的空间,防止内存泄漏。
(2)虚函数需要额外的虚函数表和虚表指针,占用额外的内存。对于不回被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当做父类时,设置为虚函数。

4、函数指针

(1)定义:函数指针是指向函数的指针变量。函数指针本身首先是一个指针变量,然后该指针变量指向一个具体的函数。C++在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量引用其他类型一样,在概念上是大体一致的。
(2)用途:调用函数和做函数的参数,比如回调函数。

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

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

6、函数重载和函数重写的区别

重载:两个函数的函数名相同,但是参数列表不同(个数、类型),返回值类型没有要求,在同一作用域中。
重写:子类继承了父类,父类中的函数是虚函数,在子类中重新定义了这个虚函数。

7、const修饰成员函数的目的是什么

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

8、在main函数之前会执行什么

全局对象的构造函数会在main函数之前执行。
写个函数在main函数执行前先运行:

attribute ((constructor))void before ()
{
printf ("before main\n");
}

9、虚函数和多态的区别

(1)多态是C++的特性,主要分为静态多态和动态多态。静态多态主要是重载,在编译的时候就已经确定;动态多态是用虚函数机制实现的,在运行期间动态绑定。比如一个父类类型的指针指向一个子类对象的时候,使用父类的指针去调用子类中重写了的父类中的虚构函数时,会调用子类重写过后的函数。在父类中生命为virtual的函数,在子类中重写时候不需要加virtual也是虚函数。
(2)虚函数的实现:在有虚函数的类中,类的最开始部分是一个虚函数表指针,这个指针指向一个虚函数表,表中放了虚函数的地址,实际的虚函数在代码段中。当子类继承了父类的时候也会继承其虚函数表,当子类重写父类中虚函数时,会将继承到的虚函数表中的地址替换为重新写的函数地址。使用虚函数会增加访问内存开销,降低效率。

10、fork函数

(1)Fork:创建一个和当前进程映象一样的进程可以通过fork()系统调用:

#include <sys/types.h>
#include <unistd.h>
pid_t fork (void);

成功调用fork()会创建一个新的进程,它几乎与调用fork()的进程一模一样,这两个进程都会继续运行。在子进程中,成功的fork调用会返回0,在父进程中fork返回子进程的pid。如果出现错误,fork返回一个负值。
(2)最常见的fork用法是创建一个新的进程,然后使用exec()载入二进制映像,替换当前进程的印象。这种情况下,派生了新的进程,而这个子进程会执行一个新的二进制可执行文件的映象。这种“派生加执行”的方式是很常见的。
(3)在早期的unix系统中,创建进程比较原始。当调用fork时,内核会把所有的内部数据结构复制一份,复制进程的页表项,然后把父进程的地址空间中的内容逐页的复制到子进程的地址空间中。但从内核角度来说,逐页的复制方式是十分耗时的,现代的unix系统采取了更多的优化,例如Linux,采用了写时复制的方法,而不是对父进程空间进行整体复制。

11、strcpy和strlen

(1)strcpy是字符串拷贝函数,原型:char str(char dest, const char *src);表示从src逐字节拷贝到dest,知道遇到‘\0’结束。因为没有指定长度,可能会导致拷贝越界,造成缓冲区溢出问题,安全版本是strncpy函数。
(2)strlen函数是计算字符串长度的函数,返回从开始到‘\0’之间的字符个数。

12、C++是怎么进行函数调用的

每一个函数调用都会分配函数栈,在栈内进行函数执行过程、调用前,先把返回地址压栈,然后把当前函数的esp指针压栈。

13、C++如何处理返回值

生成一个临时变量,把它的引用作为函数参数传入函数内。

14、C++中拷贝赋值函数的形参能否进行值传递

不能。调用拷贝构造函数的时候,首先要将实参传递给形参,这个传递的时候又要调用拷贝构造函数,如此循环,无法完成拷贝,栈也会满。

15、malloc与new的区别

malloc需要给定申请内存的大小,返回的指针需要强转。
new会调用构造函数,不用指定内存大小,返回的指针不用强转。

16、说一下static关键字的作用

(1)加了static关键字的全局变量只能在本文件中使用,不能用extern获取。
(2)加了static关键字的局部变量分配在数据段上。普通的局部变量分配在栈上,会因为函数栈的释放而被释放。
(3)对一个类中成员变量和成员函数来说,加了static关键字,则此变量(或函数)就没有了this指针,必须通过类名才能访问。

17、宏定义和函数的区别

宏定义:编译预处理指令,在编译预处理时进行简单的字符替换。
(1)宏定义的函数会在编译预处理时展开,只占编译时间,函数调用则会占用运行时间(分配单元,保存现场,值传递,返回),每次执行都要载入,所以执行相对宏会较慢。
(2)在函数调用时,先求出实参表达式的值,然后带入形参。而使用带参的宏只是进行简单的字符替换。
(3)函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。
(4)对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换;而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。
(5)宏函数的定义也有其缺点,它很容易会产生二义性。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值