学习要点:
1 虚函数 根据对象类型来调用函数 而不是根据指针类型
2 子类中的与虚函数同名函数的都是虚函数
2013-5-5补充:
这个说法有点不准确:
(1) 如果必须参数列表和返回值函数名都相同 才能认为是对虚函数的重写,仍然是虚函数
(2)函数后面有const 和 无const,可以视为两种不同函数 ,这个必须和基类中一致才能视为虚函数
在这些不一致,或者说重写虚函数不成功的情况下,只会根据指针类型来调用.
3 dynamic_cast<子类*>(父类地址)的用法 把父类地址转化为子类地址
(1) 转化类型或者 地址 必须都是多态类型 (父类中有虚函数,但子类可以重写 也可以不重写 )
(2) 父类指针必须本来指向的是子类对象才能成功,否则返回NULL
#include <iostream>
#include <string>
using namespace std;
class Person
{
protected:
string name;
private:
bool gender;
public:
Person(const char *name,bool gender):name(name),gender(gender){}
void eat(const char* food) const
{
cout << name << "吃完了" << food << endl;
}
void sleep() const; //声明可以没有定义 前提是不调用它
//虚函数 根据对象类型来调用函数 而不是根据指针类型
virtual void talk() const
{
cout << "大家好,我是" << (gender?"帅哥":"美女") <<name
<< ",很荣幸认识你!" << endl;
}
const string& Name()const
{
return name;
}
};
class Teacher: public Person
{
string course;
public:
//若要初始化父类成员,在初始化列表中把参数传给父类的构造函数(只能在初始化列表中)
//初始化列表构造顺序不决定执行顺序
Teacher(const char *name,bool gender,const char* course):Person(name,gender),course(course)
{
}
void teach(const char * _class) //class是关键字 不可以做变量名
{
cout << name << "老师在给" << _class << "讲" << course <<endl;
}
//这个是改写,不是重载,重载是同一层次的函数 参数表不同
void talk() const
{
cout << "同学们好,我是"<< course <<"老师" << name
<< ",希望能带领大家把" << course << "学好!" <<endl;
}
};
int main()
{
Person a("芙蓉",false);
Teacher b("权哥",true,"C++");
Person *p=NULL,*q=NULL;
p = &a;
q =&b;
// 多态 : 如果希望在调用时根据对象的类型调用函数 要把该函数声明为虚函数
p->talk(); //大家好,我是美女芙蓉,很荣幸认识你!
q->talk(); //同学们好,我是C++老师权哥,希望能带领大家把C++学好!
//使用父类指向子类时,若找不到函数 则会调用上一级的函数。
//使用对象直接调用时,找不到就出错。
Person c = b; //c将b多的部分截断
c.talk(); //会调用Person中的函数。 //大家好,我是帅哥权哥,很荣幸认识你!
Person &d = b; //引用的本质是指针 还是会根据对象类型找到函数
d.talk(); //调用Teacher中talk函数。//同学们好,我是C++老师权哥,希望能带领大家把C++学好!
/*
只有调用虚函数才会进行对象类型判断 并找到对象相应的函数
普通函数会根据指针类型调用函数
父类指针指向子类对象 父类对象 都可以。
子类可以指向子类对象
子类指针指向父类对象要看情况 需要检查下
dynamic_cast<子类*>(父类对象地址) 用来运行时 检查一个父类对象是否是子类对象
如果是: 返回一个正常地址,如果不是返回NULL
使用dynamic_cast 用来识别的前提是 基类中有虚函数
*/
cout << dynamic_cast<Teacher*>(p)<<endl; //0
cout << dynamic_cast<Teacher *>(q) <<endl;//0xbf91314c
cout << dynamic_cast<Teacher*>(&c) <<endl; //0
//并且这个地方有警告:warning: dynamic_cast of ‘Person c’ to ‘class Teacher*’ can never succeed
//也就是说c本来就是Person类型的,永远可能转换为Teacher型。
cout << dynamic_cast<Teacher *>(&d) <<endl;//0xbf91314c
}