类的成员函数与外部函数(静态函数)的区别
在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;
return 0;
2.可以通过内联汇编方式获取类的非静态成员函数的入口地址;
内联函数的两个作用:
1).程序的某些关键代码直接用汇编语言编写可以提高代码的执行效率;
2).有些操作无法通过高级语言来实现,或者实现起来很困难,必须借助汇编语言达到目的。例如用内联函数获取类的非静态成员函数的入口地址。
测试程序:
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;
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()
lea eax, A::print
mov v, eax
lea ecx, a
//mov ecx, a //如果将lea换成mov 则会抛出异常
p = (ptrFun)v;
return 0;
总结一下上面的代码: 可以看出即使是用了内联汇编,仍然需要一个A类对象的实例,这也就证实了一个类的非静态成员函数必须由这个类的一个实例来调用。
为什么将lea ecx, a改为 mov ecx, a 会抛出异常呢? 由于传递的不是对象的引用,所以在汇编代码中必须使用lea ecx, a, 将放在堆栈上的实参的副本地址送入寄存器ecx。
类的成员函数与外部函数(静态函数)的区别在C语言中,所有的函数都是外部函数,而在C++中,从面向对象的角度来说,由于封装的作用,函数式属于某个类的。类的静态成员函数在调用特性上与外部函数相同,因外它不依赖于类的实例。 类的成员函数与外部函数(静态函数)的区别有以下几点:1.外部函数(静态函数)可以赋值给 void* 型指针,但类的非静态成员函数不行。如果类的非静态成员函数可
Hive内置函数一 Hive函数分类二 字符函数二 类型转换函数和数学函数三 日期函数四 集合函数五 条件函数六 聚合函数和表生成函数6.1 聚合函数6.2 表生成函数:输出可以作为表使用
一 Hive函数分类
从输入输出角度分类
标准函数:一行数据中的一列或多列为输入,结果为单一值
聚合函数:多行的零列到多列为输入,结果为单一值
表生成函数:零个或多个输入,结果为多列或多行
从实现方式分类
内置函数
自定义函数
UDF:自定义标准函数
UDAF:自定义聚合函数
UDTF:自定义表生成函数
在javascript中的解释为:
函数(function)是可以执行的javascript代码块,由javascript程序定义或javascript实现预定义。函数可以带有实际参数或者形式参数,用于指定这个函数执行计算要使用的一个或多个值,而且还可以返回值,以表示计算的结果。
方法(method)是通过对象调用的javascript函数。也就是说,方法也是函数,...
在C++中,为了解决一些频繁调用的小
函数大量消耗栈空间或者栈内存的问题,引入了内联
函数。
在类中定义
成员函数会自动成为内联
函数,在类体外定义的不会,若在类体
外部定义
函数时加入 inline 关键字,会使其成为内联
函数。
这种类体外定义inline
函数的方式,必须将类的定义和
成员函数的定义都放在同一个头文件中(或同一个源文件中),否则编译时无法进行嵌入。
内联
函数一般不是我们所期望的,它会将
函数调用处用
函数体代替,所以建议在类体内部对
成员函数作声明,在类体
外部进行定义。
很多人在问 static 和extern的
区别 或者他们的用途,通过看这篇博客以及我写的全局变量的类型的那篇博客相信大家都会深深的理解他俩的用途和
区别。1.内部
函数
如果一个
函数只能被本文件中的其他
函数所调用,称它为内部
函数。内部
函数又称为静态
函数。在定义内部
函数时,在
函数名和
函数类型前加 static .如下:
static 类型标识符
函数名 ()
一、成员函数的性质
类的成员函数(简称类函数)是函数的一种,它的用法和作用和前面介绍过的函数基本上是一样的,它也有返回值和函数类型,它与一般函数的区别只是:它是属于一个类的成员,出现在类体中。它可以被指定为private(私有的)、public (公用的)或protected(受保护的)。
在使用类函数时,要注意调用它的权限(它能否被调用)以及它的作用域(函数能使用什么范围中的数据和函数)
friend
类的友元
函数是定义在类
外部,但有权访问类的所有私有(private)
成员和保护(protected)
成员。尽管友元
函数的原型有在类的定义中出现过,但是友元
函数并不是
成员函数。
友元可以是一个
函数,该
函数被称为友元
函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有
成员都是友元。
如果要声明
函数为一个类的友元,需要在类定义中该
函数原型前使用关键字 friend,
### 回答1:
这是因为成员函数是属于类的一部分,只能在类内部或者类的派生类中声明和定义。在类外部重新声明成员函数会导致编译器无法识别该函数的作用域和访问权限,从而无法正确编译。因此,成员函数只能在类内部或者类的派生类中进行声明和定义。
### 回答2:
成员函数是定义在类的内部的函数,在类的作用域内作为成员存在。因此,成员函数只能在类内部或类的派生类中被调用和使用,不能在类的外部重新声明该函数。
这是因为,在类内部定义成员函数时,系统会自动为每个成员函数添加一个类的指针作为参数,这个指针指向当前调用该函数的对象。换句话说,成员函数是依赖类的存在而存在的,只有在类的内部才能正确地调用和使用。
如果在成员函数的类外部重新声明该函数,就需要重新定义该函数的参数类型和返回类型,这样会破坏成员函数本身的设计和语义。同时,由于成员函数的定义和实现都在类的内部,这也会违背C++的函数重载机制,导致编译器无法区分同名但不同参数的函数。
因此,不能在成员函数的类外部重新声明该函数,只能在类内部进行成员函数的定义和声明,或在派生类中进行重载和覆盖。这是保证C++语法正确和保持代码清晰的重要一步,我们应该尽可能遵循这个原则。
### 回答3:
在一个类中,成员函数被定义为该类的一部分,其作用是对该类的数据进行操作。在定义一个成员函数时,可以在类的内部或外部进行声明。但是,不能在类的外部重新声明该函数。
这是因为,成员函数是该类的一部分,其定义包含在类的定义中。如果在类的外部重新声明该函数,就相当于在外部重新定义该函数,这就会导致二义性,不知道该使用哪个定义。这会使编译器产生错误,从而无法编译代码。
除此之外,在类的外部重新声明成员函数也没有实际意义。因为,成员函数本身就已经被定义在类的内部了,没有必要再在外部重新声明一遍。
相反,如果需要在类的外部调用成员函数,应该使用类的实例来调用。这样可以访问到类的实例中的成员变量,并使用成员函数对其进行操作。
总之,不能在成员函数的类外部重新声明该函数,否则会导致编译错误。因此,在定义类的成员函数时,应该遵循正确的声明和定义方式,以免产生不必要的错误。