精华内容
下载资源
问答
  • 类的成员函数与外部函数的区别

    千次阅读 2013-04-29 21:29:10
    静态成员函数在调用特性上与外部函数相同,因外它依赖于类实例。   类的成员函数与外部函数(静态函数)区别有以下几点: 1.外部函数(静态函数)可以赋值给 void* 型指针,但类非静态成员函数不行。 ...

    类的成员函数与外部函数(静态函数)的区别

    在C语言中,所有的函数都是外部函数,而在C++中,从面向对象的角度来说,由于封装的作用,函数式属于某个类的。类的静态成员函数在调用特性上与外部函数相同,因外它不依赖于类的实例。

     

    类的成员函数与外部函数(静态函数)的区别有以下几点:

    1.外部函数(静态函数)可以赋值给 void* 型指针,但类的非静态成员函数不行。

    如果类的非静态成员函数可以转换为void *型指针,那么就可以将void *型指针转换成函数指针,从而抛开对象的地址直接调用类的非静态成员函数。这样就破坏了面向对象的封装性。。。。。。。。

    例子:

    #include <iostream>
    using namespace std;
    
    void print()
    {
    	cout<<"Extenal Function\n";
    }
    
    class A
    {
    public:
    	//static void print()
    	void print()
    	{
    		cout<<"A's Member Function\n";
    	}
    };
    
    typedef void (*ptrFun)();	//定义函数指针
    
    int main()
    {
    	ptrFun p;
    	void * v;
    
    	v = (void*)&print;	//将函数地址转换为 void * 类型
    	p = (ptrFun)v;	//将void * 类型转换为函数指针
    	p();	//这样就可以调用外部函数 print()
    
    	v = (void*)&A::print;	//试图将 A::print()函数转换为void *类型的指针,,可惜这样不行
    							//如果为 A::print()为static 则不会报错
    	p = (ptrFun)v;
    	p();
    
    	return 0;
    }

     

    2.可以通过内联汇编方式获取类的非静态成员函数的入口地址;

    内联函数的两个作用:

    1).程序的某些关键代码直接用汇编语言编写可以提高代码的执行效率;

    2).有些操作无法通过高级语言来实现,或者实现起来很困难,必须借助汇编语言达到目的。例如用内联函数获取类的非静态成员函数的入口地址。

    测试程序:

     
    #include <iostream>
    using namespace std;
    
    void print()
    {
    	cout<<"Extenal Function\n";
    }
    
    class A
    {
    public:
    	//static void print()
    	void print()
    	{
    		cout<<"A's Member Function\n";
    	}
    };
    
    typedef void (*ptrFun)();	//定义函数指针
    
    int main()
    {
    	ptrFun p;
    	void * v;
    
    	v = (void*)&print;	//将函数地址转换为 void * 类型
    	p = (ptrFun)v;	//将void * 类型转换为函数指针
    	p();	//这样就可以调用外部函数 print()
    
    	//_asm
    	//{
    	//	lea eax, A::print
    	//	mov v, eax
    	//}
    	//p = (ptrFun)v;
    	//p();
    
    	_asm	//和上面的代码是一样的作用
    	{
    		mov eax, A::print
    		mov v, eax
    	}
    	p = (ptrFun)v;
    	p();
    	
    	return 0;
    }

    但是上面的代码有一个很严重的缺陷,如果A::print()需要访问A类对象的数据成员,就会引发运行错误。

    解决办法:在调用函数之前还应将类对象 的首地址送入ecx寄存器,只有这样才能保证正确的调用。

    修改之后的代码:

    #include <iostream>
    using namespace std;
    
    void print()
    {
    	cout<<"Extenal Function\n";
    }
    
    class A
    {
    public:
    	int i;
    public:
    	A(int num)
    	{
    		i = num;
    	}
    
    	//static void print()
    	void print()
    	{
    		cout<<"A's Member Function\n";
    		cout<<this->i<<endl;
    	}
    };
    
    typedef void (*ptrFun)();	//定义函数指针
    
    int main()
    {
    	A a(111);
    	ptrFun p;
    	void * v;
    
    	v = (void*)&print;	//将函数地址转换为 void * 类型
    	p = (ptrFun)v;	//将void * 类型转换为函数指针
    	p();	//这样就可以调用外部函数 print()
    
    	_asm
    	{
    		lea eax, A::print
    		mov v, eax
    		lea ecx, a
    		//mov ecx, a	//如果将lea换成mov 则会抛出异常
    	}
    	p = (ptrFun)v;
    	p();
    	
    	return 0;
    }

    总结一下上面的代码: 可以看出即使是用了内联汇编,仍然需要一个A类对象的实例,这也就证实了一个类的非静态成员函数必须由这个类的一个实例来调用。

    为什么将lea ecx, a改为 mov ecx, a 会抛出异常呢? 由于传递的不是对象的引用,所以在汇编代码中必须使用lea ecx, a, 将放在堆栈上的实参的副本地址送入寄存器ecx。

     

     


     

    展开全文
  • 静态的成员函数,同静态数据成员类似,它也是属于类,而不是属于某一个对象的。静态成员函数能访问非静态的数据...由于静态成员函数是属于类的,所以,静态成员函数的调用方法为: 类名::静态成员函数名(); 以下...

    静态的成员函数,同静态数据成员类似,它也是属于类,而不是属于某一个对象的。
    静态成员函数不能访问非静态的数据成员,它只能访问静态数据成员,也只能调用其它的静态成员函数。原因是:当前对象的地址(this)是被隐含地传递到被调用的函数的。但一个静态成员函数没有this指针,所以它无法访问非静态的成员函数。

    由于静态成员函数是属于类的,所以,静态成员函数的调用方法为:
      类名::静态成员函数名();

      以下关于静态成员变量

    1.初始化static成员变量不能安排在类的构造函数中,因为构造函数可能一再被调用,而变量的初值却只应该设定一次。也不要把初始化安排在头文件中,因为它可能会被包含在许多地方。而应该放在main函数之中,或全域函数中,或者任何函数之外。

    //=====================================

       对于多个的C/C++头文件的包含,一般情况下放在工程的目录下编译器就可以正确地找到。 但是对于在不同文件夹下的头文件的包含,当然可以写完整的路径,但是这样有可能会出现将工程拷到别人的机子上运行不了的问题。如果在这个程里同写上相对的路径,那么不仅在自己的机子上能运行,别人拷了过去也能正确运行。

     

     

       例如我的一个工程头文件如下:

          c:/F/Work/test/testnow/testPage.h

     

     

    上面的头文件要包含的文件如下:

    c:/F/Work/test/testnow/FileHelpers/FileInformationList.h

    c:/F/Work/test/testnowTray/testTray/Share.h

     

     

    那么可以在testPage.h上这样写:

    [cpp] view plaincopy

    #include "./FileHelpers/FileInformationList.h"  

    #include "../testnowTray/testTray/Share.h"  

     

    上面

    #include "./FileHelpers/FileInformationList.h"

    的一点表示当前目录(这些的标记对于接触过DOS的人来说一定不会陌生吧?)

    #include "../testnowTray/testTray/Share.h"

    的两点表示上一级目录。

     

    其他的照这样类推。  这样是不是方便了一点???

    展开全文
  • 要达到这一点,成员函数的成员属性不会给其带来额外的负担。考虑以下两种函数调用:前者需要传入一个类指针,属于非成员函数调用,后者直接指明Animal类的函数调用。本质上,这两个函数是一样的
  • 静态成员使用遵循以下几点: ...静态成员是属于类而不是属于对象,占用对象空间,但对象可以引用它,需要使用特殊格式,是所有对象共有,一旦改变,各对象都跟着改变; 普通成员函数可...

    静态成员使用遵循以下几点:

    1. 静态成员变量不能通过参数列表来初始化,只能在类外初始化(int ClsTest::total = 0;),如果不初始化则为编译器默认值;
    2. 静态成员常量可以在类内定义时直接初始化也可以像静态成员变量一样类内声明,类外定义;
    3. 静态成员是属于类而不是属于对象,不占用对象的空间,但对象可以引用它,不需要使用特殊的格式,是所有对象共有,一旦改变,各对象都跟着改变
    4. static成员依然保持public,private,protected访问准则;
    #include <iostream>
    
    using namespace  std;
    
    class ClsTest
    {
    public:
    	static int total;
    private: 
    	static const int rate = 100;	// 静态成员常量可以直接初始化,static const 等于 const static
    };
    
    int ClsTest::total = 0;				// 必须在外部初始化,且不需要加static 
    // const int ClsTest::rate = 100;	// 静态常量也可以在外部初始化 
    
    int main()
    {
    	ClsTest t1, t2;
    	
    	t1.total = 100;
    	cout << "Total 1: " << t2.total << endl;
    	cout << "Total 2: " << ClsTest::total << endl; 	// 各个对象都跟着变化,这2种方式都可以访问 
    	//cout << "Rate: " << ClsTest::rate << endl;	// 不能访问私有 
    	
    	return 0;
    }
    
    /*
    输出结果:
    Total 1: 100
    Total 2: 100
    */
    
    1. 普通成员函数可以引用所有的成员(不管是否为静态),而静态成员函数只能使用静态成员而不能访问其他非静态成员
    #include <iostream>
    
    using namespace  std;
    
    class ClsTest
    {
    public:
    	static void s_func(){
    		s_test();
    		//test();	// 不可以引用非静态成员(包括函数和变量) 
    	}
    	void func(){
    		s_test();
    		test();
    	}
    private:
    	static void s_test(){
    		cout << "s_test" << endl;
    	}
    	void test(){
    		cout << "test" << endl;
    	}
    };
    
    int main()
    {
    	ClsTest t1;
    
    	t1.s_func();
    	t1.func();
    	
    	return 0;
    }
    /*
    输出结果:
    s_test
    s_test
    test
    */
    
    1. 子类继承之后依然保持着静态变量,不需要重复初始化
    #include <iostream>
    
    using namespace  std;
    
    
    /* 类ClsTest */ 
    class ClsTest
    {
    public:
    	static int total;
    };
    int ClsTest::total = 0;
    
    
    /* 类ClsTest2继承ClsTest */ 
    class ClsTest2 : public ClsTest
    {
    
    };
    // int ClsTest2::total = 0;			// 错误,已经在ClsTest定义初始化,无须重复 
    
    
    int main()
    {
    	ClsTest t1;
    	
    	t1.total = 100; 	
    	cout << "Total 1: " << ClsTest::total << endl;
    
    	ClsTest2 t2;
    	cout << "Total 2: " << t2.total << endl;
    	cout << "Total 3: " << ClsTest2::total << endl; // 子类保持着静态成员的值 
    	
    	return 0;
    }
    /*
    输出结果:
    Total 1: 100
    Total 2: 100
    Total 3: 100
    */
    
    展开全文
  • 因此可以看出,每个对象占用存储空间只是该对象数据部分(虚函数指针和虚基类指针也属于数据部分)所占用存储空间,而包括成员函数所占用存储。 测试代码 代码如下,以下代码输出结果是什么? cl...

    成员函数和成员变量存储说明

    C++中类的成员函数和成员变量的存储方式是不一样的。比如定义对象是系统会为对象分配存储空间,其中只为成员变量分配了存储空间,而成员函数则存放在公共的代码段中。如下图所示:

    在这里插入图片描述

    因此可以看出,每个对象占用的存储空间只是该对象的数据部分(虚函数指针和虚基类指针也属于数据部分)所占用的存储空间,而不包括成员函数所占用的存储。

    测试代码

    代码如下,以下代码的输出结果是什么?

    class Test
    {
    public:
    	void function1()
    	{
    		cout<<"in func1"<<endl;
    	}
    
    	void function2()
    	{
    		cout<<"in func2"<<endl;
    	}
    };
    int main()
    {
    	Test* t = NULL;
    	t->function1();
    	t->function2();
    
    	return 0;
    }
    

    答案:输出 in func1后,程序崩溃
    原因:function1是成员函数,存放在代码段(.text),所以没有实例化类的时候仍然可以调用。function2是虚函数,关系到虚函数表和虚函数指针,虚函数指针存放在实例化的对象中,所以,未实例化对象时,不存在虚函数指针,所以调用虚函数会报错

    inline函数:需要说明,不论成员函数在类内定义还是在类外定义,成员函数的代码段都用同一种方式存储。不要将成员函数的这种存储方式和inline(内联)函数的概念混淆。不要误以为用inline声明(或默认为inline)的成员函数,其代码段占用对象的存储空间,而不用inline声明的成员函数,其代码段不占用对象的存储空间。不论是否用inline声明(或默认为inline),成员函数的代码段都不占用对象的存储空间。用inline声明的作用是在调用该函数时,将函数的代码段复制插人到函数调用点,而若不用inline声明,在调用该函数时,流程转去函数代码段的入口地址,在执行完该函数代码段后,流程返回函数调用点。inline与成员函数是否占用对象的存储空间无关,它们不属于同一个问題,不应搞混。


    C++程序的存储分布

    C++程序的内存格局通常分为四个区:全局数据区(data area),代码区(code area),栈区(stack area),堆区(heap area)(即自由存储区)。

    • 全局数据区存放全局变量,静态数据和常量;
    • 所有类成员函数和非成员函数代码存放在代码区;
    • 为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区;
    • 余下的空间都被称为堆区。
      由此,我们可以得知在类的定义时,类成员函数是被放在代码区,而类的静态成员变量在类定义时就已经在全局数据区分配了内存,因而它是属于类的。对于非静态成员变量,我们是在类的实例化过程中(构造对象)才在栈区或者堆区为其分配内存,是为每个对象生成一个拷贝,所以它是属于对象的。

    类的静态成员函数和非静态成员函数的区别

    静态成员函数和非静态成员函数都是在类的定义时放在内存的代码区的,因而可以说它们都是属于类的,但是类为什么只能直接调用静态类成员函数,而非静态类成员函数(即使函数没有参数)只有类对象才能调用呢?原因是类的非静态类成员函数其实都内含了一个指向类对象的指针型参数(即this指针),因而只有类对象才能调用(此时this指针有实值)上面的测试代码中this的值是NULL,NULL也是一个实值

    展开全文
  • c++类成员函数作回调

    2018-12-17 14:52:04
    1,类static函数,由于此类函数属于类而非类实例,存在this指针概念,因此可以直接取其函数地址作为回调; 2,类普通成员函数,这类函数在实现上存在着隐含this指针,因此作为回调必须指明是哪一个类...
  • static数据成员与static成员函数

    千次阅读 2013-05-13 11:51:45
    每个类只有一个存储单元,静态数据成员为该类所有对象共有,不属于某个对象。静态数据成员的初始化必须在类以外进行定义性说明。 形式为:类型> 类名>::静态数据成员> =值 静态成员注意以下几点: 1、静态...
  • 我认为以下这两种解释都是类似,正确: 解答一:static 只能修饰 成员变量 或者成员方法。能修饰局部变量。在Java 中,用static 修饰的成员 被是为 共享。定义在方法中,被视为 局部。显然是能共享...
  • 而对话框串口的成员变量属于对话框类,所以能调用,若想使用,可以自定义一个消息,在线程函数中利用SendMessage or PostMessage函数给主窗口发送消息,然后在窗口类实现文件中定义消息处理函数即可,主要有以下...
  • 什么函数不能声明为虚函数

    千次阅读 2016-09-06 14:13:00
    函数的目的是为了实现多态,多态和集成有关,所以声明一个非成员函数为虚函数没有任何意义。 2)静态成员函数不能是虚函数。静态成员函数对于每一个类只有一份代码,所有的对象共享这份代码,它归某个对象所有,...
  • 3.如果对成员函数进行重载,重载的函数与被重载的函数应该是用一个类中的成员函数能分属于两个不同继承层次的类,函数重载处理的是横向的重载。虚函数是对同一类族中的基类和派生类的同名函数的处理,即允许在...
  • 只能用解释器来解释执行【多选题】下面哪些打印机属于3D打印机【单选题】以下不是3D打印技术需要解决问题是( )【单选题】SLA技术中文全称是_____【判断题】在Python中可以为自定义类对象动态增加新成员。...
  • 首先呢我们知道c++类中成员分为成员变量和成员函数两大类,如果再加上static给以区分话那么会有以下四种:静态成员变量,非静态成员变量;静态成员函数,非静态成员函数  (1)成员变量  我们知道类静态成员...
  • 使用静态函数的好处

    千次阅读 2015-10-23 16:00:25
    1.静态成员函数实际上是一个全局函数,依赖一个类对象,而属于创建对象也可调用(实例化也可以使用)  普通成员函数依赖一个类对象,也就是它有一个隐藏调用参数(this)指针,必须指向一个类对象...
  • C++中静态函数

    2012-10-09 14:53:34
    一些有关C++中静态函数的东西 以下内容大部分从网上找来 这篇文章属于介绍的比较基础的东西 ...63d2328323edf129!...静态成员函数不能访问非静态的数据成员,它只能访问静态数据成员,也只能调用其它的静态
  • static修饰成员函数Summary 在C/C++中,局部变量按照存储形式可以分为以下三种:auto、static、register。默认是auto,auto类型(普通)局部变量分配于栈上,属于动态存储类型,函数调用完成之后会存储空间...
  • 静态成员

    2017-06-28 00:20:30
    (1)类静态成员是属于类而不属于对象,所以他不是类单个对象所有。(2)静态成员只存在一个,不像普通的成员,每创建一个对象,就会创建一组普通的成员。(3)静态成员变量初始化不能在类中,肯定是不能在...
  • C++11新特性(85)-类类型union成员(1)

    千次阅读 2018-10-17 08:34:36
    这个新特性涉及的内容较多,所以本文先做一些不属于C++11新特性的准备工作。   匿名union 我们通过一个例子类说明。假设有以下函数: 这 个函数的功能是根据参数rt的要求产生随机数并转换为字符串。代码中...
  • 一、 static 变量 static变量大致分为三种用法1....表示这个成员是属于这个类但是不属于类中任意特定对象1. 静态局部变量静态局部变量属于静态存储方式,它具有以下特点:(1)静态局部变量在函数内定义 它
  • 一、 static 变量 static变量大致分为三种用法 ...表示这个成员是属于这个类但是不属于类中任意特定对象 1. 静态局部变量 静态局部变量属于静态存储方式,它具有以下特点: (1)静态局部变量在函数...
  • 这个构造函数属于,而不是属于哪里实例,就是说这个构造函数只会被执行一次。也就是在创建第一个实例或引用任何静态成员之前,由.NET自动调用。 以下是引用片段:  class SimpleClass  {  // ...
  •  (1)友元函数不是类的成员,不带this指针,必须通过对象名或者对象的引用作为友元函数的参数来访问对象的成员。友元函数必须在类定义中说明(但是对友元函数指定访问权限无效,因为友元函数不属于类,所以在类中...
  • C++友元函数与友元类

    2021-03-15 15:12:59
    友元函数是一个可以访问类私有成员的函数,并且它不属于这个类。 友元类则是可以访问另一个类私有成员的类。 声明友元函数/友元类,则需要这样做: 比如,我们需要生命ClassTwo是ClassOne友元类,那么...

空空如也

空空如也

1 2 3 4 5 6
收藏数 107
精华内容 42
关键字:

以下不属于成员函数的是