2007-6-24 14:11
如果不考虑权限的问题, C++中类的成员函数, 其实就是被编译器改了个名字,对非静态的,又加了个this参数
(ps:this指针 只是每个非静态成员函数隐含的参数,参数传入不压栈,通过ECX传入函数 )
程序设计的模块化,可以通过提升编程语言的功能和设计精巧的数据结构来实现
虚函数
基类指针只能访问基类中的成员函数,不能访问派生类中的成员函数,这样就不能通过同一指针对一系列的对象实现一般化操作。
(ps:为了防止指针的误操作,C++语法规定,一种类型的指针不能指向另一种类型的变量,但有一个例外,允许一个基类的指针指向其派生类的对象。但是通过该指针也只能访问派生类中从基类继承来的公有成员,不能访问派生类中新增的成员,除非通过强制类型转换将基类的指针转换为派生类的指针,另外派生类的指针是不允许指向基类的对象的)。
为了解决这个问题,引入虚函数,虚函数通过一个精巧且常用的数据结构来实现。C++为每一个含有虚函数的类构造一个虚函数表(vtable),并为这个类增加一个成员变量(vptr),用来指向这个虚函数表。
虚函数表中的每一项为当前类中的虚函数名和对应的虚函数的地址。派生类会继承基类的虚函数表,如果在派生类中改写了一个虚函数,就会去改写虚函数表,将虚函数名对应的函数地址更新为当前的虚函数地址。程序执行时,基类指针根据虚函数表找到正确的函数地址。其实就是编译时在调用虚函数的地方不是直接给出函数地址,而是在执行的时候通过指向对象的虚函数表找到函数地址
(ps:纯虚函数:virual void func() = 0; 拥有纯虚函数的类叫抽象类,抽象类不能用来生成实例,只能被继承,如果被继承后仍没有改写所以纯虚函数,则仍为抽象类 )
(ps:以单一指令调用不同的函数,这叫多态(Polymorphism) 除了虚函数,多态还有函数重载和运算符重载两种形式,函数重载是依靠C++编译器对函数的命名方法来实现的,这是对C语言的一个改进 关于编译器的命名方法和命名空间的问题,再谈:)
成员函数的指针
关于成员函数的指针,又是一个比较特殊的问题,成员函数的指针和一般的函数指针不一样,普通的函数指针本质就是一个long型的变量,存储函数的起始地址,而类的成员函数的指针其实是个结构体,成员函数的指针不光要包含成员函数的地址,还要包含引用成员函数的对象的信息。下面给个成员函数指针用法的例子,
{
public:
int a;
void ca_fun() {
printf("ca_fun %d
", a);
}
void ca_fun2() {
void (CA::*fp)(); // 定义
fp = &CA::ca_fun; // 赋值
(this->*fp)(); //调用
}
};
PS:
编译器提供了几个新的操作符来支持成员函数指针操作:
1) 操作符"::*"用来声明一个类成员函数指针,例如:
typedef void (Base::*PVVBASEMEMFUNC)(void); //Base is a class
2) 操作符"->*"用来通过对象指针调用类成员函数指针,例如:
(pBase->*pVIBaseMemFunc)();
3) 操作符".*"用来通过对象调用类成员函数指针,例如:
(baseObj.*pVIBaseMemFunc)();