面试题答案
一键面试内存布局不同点
- 存储位置:
- 普通函数:普通函数在程序的代码段(text segment)存储。代码段是只读的,用来存放程序的机器代码。在C++中,普通函数的所有实例(如果是成员函数,针对不同对象实例调用)共享这一份代码。例如一个类
A
的普通成员函数void A::func()
,无论创建多少个A
的对象,调用func
时执行的都是代码段中同一份函数代码。 - static函数:静态函数同样存储在程序的代码段。无论是类的静态成员函数还是普通的静态函数(在文件作用域定义的使用
static
修饰的函数),它们也都位于代码段。例如class B { static void staticFunc(); };
,B::staticFunc
和在文件作用域定义的static void globalStaticFunc()
都在代码段。从存储位置角度,static函数和普通函数在这方面没有区别。
- 普通函数:普通函数在程序的代码段(text segment)存储。代码段是只读的,用来存放程序的机器代码。在C++中,普通函数的所有实例(如果是成员函数,针对不同对象实例调用)共享这一份代码。例如一个类
- 可见性和链接属性:
- 普通函数:默认具有外部链接属性(external linkage)。这意味着在多个源文件的项目中,如果一个普通函数在一个源文件中定义,其他源文件可以通过声明来调用这个函数。例如在
file1.cpp
中定义void normalFunc() {}
,在file2.cpp
中可以声明void normalFunc();
然后调用。它在整个程序中可见(当然前提是遵循作用域规则)。 - static函数:
- 类的静态成员函数:类的静态成员函数的可见性局限于类的作用域内。例如
class C { static void staticMemberFunc(); };
,staticMemberFunc
只能在类的内部或者通过类名或对象来调用,在类外没有直接可见性。 - 普通的静态函数(文件作用域):在文件作用域定义的静态函数具有内部链接属性(internal linkage)。它只在定义它的源文件内可见,其他源文件无法访问。例如在
file3.cpp
中定义static void fileStaticFunc() {}
,在其他源文件中不能直接调用fileStaticFunc
。
- 类的静态成员函数:类的静态成员函数的可见性局限于类的作用域内。例如
- 普通函数:默认具有外部链接属性(external linkage)。这意味着在多个源文件的项目中,如果一个普通函数在一个源文件中定义,其他源文件可以通过声明来调用这个函数。例如在
- 与对象的关系:
- 普通成员函数:普通成员函数与对象实例紧密相关,通过对象来调用(对于非
static
成员函数)。每个对象都有一个隐含的this
指针,在调用普通成员函数时,this
指针指向调用该函数的对象实例,通过this
指针可以访问对象的成员变量等。例如class D { int data; void normalMemberFunc() { data = 10; } };
,当D d; d.normalMemberFunc();
时,normalMemberFunc
中的this
指针指向d
对象,从而可以修改d
对象的data
成员变量。 - 静态成员函数:静态成员函数不与特定的对象实例关联。对于类的静态成员函数,它没有隐含的
this
指针,因为它不是针对某个具体对象调用的。例如class E { static int sData; static void staticMemberFunc() { sData = 20; } };
,staticMemberFunc
不能直接访问非静态成员变量,只能访问静态成员变量(如sData
)。
- 普通成员函数:普通成员函数与对象实例紧密相关,通过对象来调用(对于非
产生差异的原因
- 存储位置相同的原因:无论是普通函数还是static函数,它们本质上都是可执行代码,所以都存储在代码段以实现代码的共享和只读特性,这是程序运行时对可执行代码管理的基本方式。
- 可见性和链接属性差异的原因:
- 普通函数的外部链接:普通函数的外部链接属性是为了方便在大型项目中不同源文件之间的代码复用和协作。不同模块可以调用其他模块定义的普通函数,实现程序功能的组合。
- 类静态成员函数的类作用域可见性:类的静态成员函数主要是为了提供与类相关但不依赖于具体对象实例的功能,将其可见性限制在类作用域内,符合面向对象编程对封装和信息隐藏的要求,防止外部随意访问类内部的静态功能。
- 文件作用域静态函数的内部链接:在文件作用域定义的静态函数具有内部链接属性,是为了防止不同源文件中同名函数的冲突。它使得函数的作用范围局限在本文件,提高了代码的模块化和可维护性,不同源文件可以定义同名的静态函数而互不干扰。
- 与对象关系差异的原因:普通成员函数与对象实例相关,是因为它通常需要访问和操作对象的成员变量,通过
this
指针来明确操作的具体对象。而静态成员函数主要处理与类相关的通用逻辑,不依赖于某个具体对象的状态,所以不需要this
指针,这样设计使得静态成员函数更侧重于类层面的功能实现,而非对象个体的操作。