(转)c++类的成员函数存储方式(是否属于类的对象)---一道面试题引发的思考

昨天去面试一家公司,面试题中有一个题,自己没弄清楚,先记录如下:

class D
{
public:
    void printA()
    {
        cout<<"printA"<<endl;
    }
    virtual void printB()
    {
        cout<<"printB"<<endl;
    }
};

main函数调用:

D *d=NULL;
d->printA();
d->printB();

输出结果是?

当时想的是对象d直接初始化为NULL,非虚的成员函数没有地址,应该找不到,而virtual成员函数,由于对象会有指向虚拟函数表的指针-vptr,指向virtual函数列表的虚拟函数表,这样应该能够取到地址(实际上,这个virtual函数的printB最应该想到是直接崩溃,因为d指向NULL,即地址为0x00000000,再去找虚地址指针,肯定是不允许的)。

下面具体分析一下吧

先看一下类的成员函数的情况,

类A、B、C三个类,一个是什么都没有的真的空类,一个是有成员函数的类,最后一个是带有虚函数的类。

class A
{

};
class B{
public:
    B(){}
    ~B(){}
};
class C
{
public:
    C(){}
    virtual ~C(){}
};

那他们分别咱的内存大小是多少呢?

cout<<"A="<<sizeof(A)<<endl;
cout<<"B="<<sizeof(B)<<endl;
cout<<"C="<<sizeof(C)<<endl;

32位windows xp机器上测试结果:

A=1

B=1

C=4

从A和B的比较可以看出成员函数是不占用类空间的,再具体一个例子:

class E{
public:
    E(){}
    ~E(){}
private:
    int m_data;
    char c;
};

sizeof(E)在32位机器上输出结果,如果不考虑对齐 为5,考虑则为8,可见和上面B类的预期一致。

我们可以说,静态数据成员和静态成员函数时类的一部分,而不是对象的一部分(谭老师说的)。

当我们实例化一个对象的时候,因为这个对象是用类定义的,那么它理所当然拥有了这个类的数据和函数。但是,一般情况下,不同的对象,他们的的数据值不同,但是函数的代码都相同。所以,为了节约存储空间(想象一下我们如果定义了100个对象,那么用100段内存空间存储相同的代码,岂不是很浪费?),我们让成员函数的代码共享。

我们把成员函数的代码存储在对象空间之外。换句话说,成员函数的代码,都不占据对象的存储空间。它会被存在其他地方。

所以类的成员函数,对于类来讲。一方面是逻辑上的“属于”,一方面是物理上的“不依赖“。

回到思考题上来,对于非静态成员函数来说,它当然是对象的一部分。(只是因为存储方式上的特殊性,容易让人误解!)

回答开头问题:

类中包括成员变量和成员函数
new出来的只是成员变量,成员函数始终存在
所以如果成员函数未使用任何成员变量的话,不管是不是static的,都能正常工作

一个对象的空间=所有成员变量的大小

如果这个对象的类有虚函数的话,还可能多一个指向虚表的指针

所有函数存放在独立于对象的存储空间内
对象调用函数时,对静态成员函数直接调用不存在问题,对成员函数需要把自己以this指针传给函数以指明以哪个对象调用

所以用未初始化的指针调用静态成员函数、或者调用未使用任何成员变量的成员函数(即未用到this指针)
从理论上都是可行的,至于具体支不支持看各个编译器吧

思考:

main函数中,如果

D d;//=NULL;
    d.printA();
    d.printB();

调用呢?

都能正常输出,d在栈上。。。

时间: 2024-12-26 06:09:56

(转)c++类的成员函数存储方式(是否属于类的对象)---一道面试题引发的思考的相关文章

C++类的成员函数存储方式(是否属于类的对象)

今天在看TAF源码的时候,发现下面一段有趣的代码: getSmallerProxyPrx = Application::getCommunicator()->stringToProxy<GetSmallerPrx>(MobileAssist.JiangeSmallerServer.GetSmaller); //此处T为GetSmallerPrx template<class T> T stringToProxy(const string& objectName,con

C++:类的成员函数定义方式

1.成员函数的第一种定义方式:在类声明中只给出成员函数的原型,而将成员函数的定义 放在类的外部. 返回值类型 类名::成员函数名(参数表) {      函数体  } class Point{ public: void setpoint(int,int); //设置坐标点的成员函数setpoint的函数原型 int getx(); //取x坐标点的成员函数getx的函数原型 int gety(); //取y坐标点的成员函数gety的函数原型 private: int x,y; }; void P

【C/C++学院】0819-/类的成员函数与const-mutable /构造与析构/拷贝构造deletedefault以及深浅拷贝/静态成员函数成员变量类在内存的存储默认参数/友元类以及友元函数

类的成员函数与const-mutable 成员函数 Fushu.h #pragma once #include <iostream> class fushu { public: int x; int y; public: fushu(); ~fushu(); void show(); inline void showall(int x, int y);//显式内联 void setxy(int x, int y);//编译器优化,默认隐式内联 void show(int x, int y);

C++类的成员函数使用的一些小总结

From: http://blog.csdn.net/xiayefanxing/article/details/7607506 这一阵做项目代码开发的时候,用到了在一个C++文件中使用另一个类的成员函数的问题,做个小总结. 其中有些是网上搜索的资料,因为比较分散就不一一给出出处了,请作者见谅. 1.C++如何在一个类的成员函数中调用另一个类的成员函数? 假设你想在类A里调用类B的函数int f(x),两种办法: (1)class A::B 也就是说将B定义为A的父类, 这样你就可以自然的在A里面

在类外部定义类的成员函数

#include <stdio.h> class A {    public:    int b;             void   print1 (); }; void A:: print1() //在类外部定义类的成员函数时候必须加上所属类的类名 { printf("打印"); }  void main() {             A a;    a.print1();    getchar(); }

C++成员函数存储

用类去定义对象时,系统会为每一个对象分配存储空间.如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间. 按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元,如图8.4所示. 图8.4 能否只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码.如图8.5所示. 图8.5 显然,这样做会大大节约存储空间.C++编译系统正是这样做的,因此每个对象所占用的存储空间只是该对象的数据部分所占用的存储空间,而不包括函

const修饰类的成员函数

<Effective C++>里面说,尽量使用const,const修饰变量一般有两种方式:const T *a,或者 T const *a,这两者都是一样的,主要看const位于*的左边还是右边,这里不再赘述,主要来看一下当const修饰类的成员函数时,成员函数有什么特点. 类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态数据成员)作任何改变. 在设计类的时候,一个原则就是对于不改变数据成员的成员函数都要在后面加 const,而对于改变数据成员的成员函

C++类的成员函数的指针和mem_fun适配器的用法

一.普通函数指针 我们先来看一个最简单的函数: void fool(int a) { cout << a<< endl; } 那么它的函数指针类型为: void (*) (int) 我们可以这样测试: void (*pFunc)(int) = &foo;//这里pFunc是个指针 pFunc(123); 这样就会打印出整数123:为了简化,我们可以使用typedef: typedef void (*pFunc)(int); 这里我们要说明一下: 这里的pFunc是 返回值为

类的成员函数指针和mem_fun适配器的用法

先来看一个最简单的函数: void foo(int a) { cout << a << endl; } 它的函数指针类型为 void (*)(int); 我们可以这样使用: void (*pFunc)(int) = &foo; pFunc(123); 这就是函数指针的基本使用.   类的成员函数   那么,对于类的成员函数,函数指针有什么不同呢? 我们观察下面的类: class Foo { public: //void (Foo::*)(int) void foo(int