C/C++学习----第三章 多态性和虚函数
2006-10-27 10:34
495 查看
第三章 多态性和虚函数
3.1 多态性
3.1.1 编译时的多态性——重载
重载的特征是:各个函数的名字相同,但参数个数或参数的类型不同。在派生类中调用基类的重载函数时,必须带有基类名和域作用符(::),否则引起派生类函数的无限循环调用。
<1>在一个类中进行重载
<2>基类成员函数在派生类中重载
<3>类外部函数的重载
在C++中,大多数系统预定义的运算符都可以重载。除以下运算符:. :: .* ?: sizeof
class point {
int x, y;
public:
point(int x, int y);
point operator +( point p); //重载运算符+
point operator -( point p); //重载运算符-
point operator =( point p); //重载运算符=
}
重载不能建立新的运算符,也不能改改变运算符的优先级、结合性和操作数的个数。赋值运算符(=)和地址运算符(&)无需重载就可以用于每一个类。
3.1.2 运行时的多态性——虚函数
多态性是通过虚函数实现的,体现在:通过基类指针(或引用)请求使用虚函数时,C++会在与对象关联的派生类中正确的选择重定义的函数。派生类指针调用成员函数时,不是多态性行为;以对象与“.”符调用虚函数,也不是多态性行为。对象指针:
<1>可以让一个指向基类的指针指向公有派生的对象,但是不能指向一个私有派生的对象。<2>不能将一个指向派生类的指针指向基类对象
<3>声明为基类对象的指针,当指向派生类对象时,只能利用它来访问派生类中从基类继承来的成员,不能直接访问公有派生类中特定的成员。如果要访问公有派生类中的特定成员,需要将基类指针显式类型转换为派生类指针来实现(如下表左部)。
class A { public: print(); }; class B: public A{ public: print(); }; void main() { B b, *pb; A a, *pa; pa = &b; pa->print(); //访问类A中的print ((B *)pa)->print(); //访问类B中的print } | class A { public: virtual print(); }; class B: public A{ public: print(); }; void main() { B b, *pb; A a, *pa; pa = &b; pa->print(); //访问类B中的print } |
虚函数:
在基类中,声明了一个虚函数,在它的派生类中可被重新定义,函数的原型必须完全一致(不同于基类和派生类中的函数重载),否则系统会认为是函数重载;如果仅仅时返回值不同,参数类型和格数完全相同,系统认为是一种语法错误。指向基类的指针,当它指向不同的派生类对象时,调用不同对象的成员函数(体现了动态多态性)。实现虚函数需要对象附带一些额外信息,以使对象在运行时可以确定该调用哪个虚函数。对大多数编译器来说,这个额外信息的具体形式是一个称为vptr(虚函数表指针)的指针。vptr指向的是一个称为vtbl(虚函数表)的函数指针数组。每个有虚函数的类都附带有一个vtbl。当对一个对象的某个虚函数进行请求调用时,实际被调用的函数是根据指向vtbl的vptr在vtbl里找到相应的函数指针来确定的。详细请参见F:/useful/ATL Under the Hood.doc
多继承中的虚函数:
虚函数特性是可以传递的,多个基类的公共基类中的虚函数可以传递给多重派生类,基类指针不能指向派生类的派生类对象。
class A {
public:
virtual void print();
};
class B{
public:
void print( );
};
class C: public A, public B{
public:
void print( );
};
void main()
{
A a, *pa;
B b, *pb;
C c;
pa = &c; pa->print();
pb = &c; //调用C中的print, 体现虚函数特性
pb->print();//调用基类B中的print,体现重载函数特性
}
纯虚函数:
纯虚函数是一个在基类中声明的虚函数,但在基类中没有定义,要求所有派生类必须定义自己的版本。形式:virtual type funname(参数表)=0;如果在抽象类的派生类中,没有提供纯虚函数的定义,该函数仍为纯虚函数,该类为抽象类。抽象类:
如果一个类至少有一个纯虚函数,则称为抽象类。对抽象类<1>不能建立抽象类的对象
<2>抽象类不能用作参数类型,函数返回值或显式转换的类型
<3>可以声明抽象类的指针和应用,此指针可以指向派生类,实现多态性。
class awov { // awov = "abstract w/o
// virtuals"
public:
virtual ~awov() = 0; //声明一个纯虚析构函数
};
这个类有一个纯虚函数,所以它是抽象的,而且它有一个虚析构函数,所以不会产生析构函数问题。但这里还有一件事:必须提供纯虚析构函数的定义:
awov::~awov() {} // 纯虚析构函数的定义
这个定义是必需的,因为虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。这就是说,即使是抽象类,编译器也要产生对~awov的调用,所以要保证为它提供函数体。
相关文章推荐
- C/C++学习----第三章 多态性和虚函数
- C++学习之路—多态性与虚函数(一)利用虚函数实现动态多态性
- C++ 学习之路(11):多态性与虚函数
- c++新手学习笔记之多态性和虚函数(1)
- C++程序设计学习之『多态性与虚函数』
- C++学习笔记――多态性和虚函数
- C++第十三周【任务1】开车学习虚函数、多态性和抽象类的应用
- 一步一步学习C++(类)之多态性与虚函数
- C/C++学习(1)面向对象的多态性问题、虚函数调用
- C++学习之路—多态性与虚函数(二)纯虚函数与抽象类
- C++学习7-面向对象编程基础(多态性与虚函数、 IO文件流操作)
- C++学习笔记13:类继承和派生、虚函数
- C++多态性基本概念 包括虚函数和纯虚函数
- C++之多态性与虚函数
- C++-虚函数,多态性,纯虚函数,抽象类
- C++学习 虚函数和纯虚函数的区别
- C++ 虚函数内存布局学习笔记
- 一步一步学习C++(类)之虚函数和纯虚数
- C++学习笔记第三天:类、虚函数、双冒号
- C++多态性及虚函数