asp企业网站源码,优化网站搜索排名,网站交换链接怎么做?,谷歌浏览器在线入口类与对象
多态
1. 简介
一个事物的多种形态#xff0c;简称多态。 物的多态 同一个人在不同人面前#xff0c;角色不同 如#xff1a; 在父母面前在对象面前在朋友面前在同事面前 事的多态 同一种事情#xff0c;在不同情况下展现不同 如#xff1a; 吃饭 中国人 筷子 …类与对象
多态
1. 简介
一个事物的多种形态简称多态。 物的多态 同一个人在不同人面前角色不同 如 在父母面前在对象面前在朋友面前在同事面前 事的多态 同一种事情在不同情况下展现不同 如 吃饭 中国人 筷子 熟食美国人 刀叉 7分熟印度人 手 咖喱饭 睡觉 中国人 床上日本人 地上 平躺 侧卧 趴着
2. 上行与下行
2.1 上行
子类 转 父类
语法
父类名 *父类对象指针 子类对象指针;
或
父类名 父类对象名 子类对象;注意 无风险无需强转。 2.2 下行
父类 转 子类
语法
子类名 *子类对象指针 (子类名 *)父类对象指针;
或
子类名 子类对象 (子类名) 父类对象;注意 有风险需强转。 2.3 示例
#include iostream
using namespace std;class Anim{
public:int a;Anim(){}Anim(int a):a(a){}
};class Dog:public Anim{
public:int d;Dog(){}Dog(int a, int d):Anim(a),d(d){}
};
class Cat:public Anim{
public:int c;
};int main(int argc, char *argv[])
{//上行//将子类对象的地址赋值给父类对象的引用或指针Dog d1(10, 100);Anim a1 d1;//赋值给指针记得取地址不然报错Anim* a2 d1;cout d1.d d1.d endl; //d1.d100cout a1.a a1.a endl; //a1.a10//子类转父类后, 父类对象不能使用子类所特有的属性
// cout a1.d a1.d endl; //报错//下行Dog d2 (Dog )a1;Dog *d3 (Dog *)a2;cout d2.d d2.d endl; //d2.d100//父类转换子类后,子类可以使用父类的cout d2.a d2.a endl; //d2.a10//下行父转子Cat c1 (Cat )a1;cout c1.a c1.a endl; //c1.a10//d1的内存中没有c,所以c1.c 的值为 d1中d的值cout c1.c c1.c endl; //c1.c100return 0;
}分析 Dog继承了 Anim所以d1对象中 有a 也有 d父转子c1也指向 d1可能会报错编译器优化可能也不报错 3. 重写
继承关系中返回值类型相同函数名形同形参列表相同函数体不同 。 重载 同一作用域下,函数名相同,形参列表不同重定义 继承关系中,函数名相同即可。一旦重定义后子类会将父类的函数覆盖掉4. c多态分类
多态分为 物的多态上行、下行 事的多态静态多态动态多态
4.1 静态多态(早绑定静态联编)
概念: 在编译阶段 就确定函数的入口地址 又名: 静态联编早绑定 如: 函数重载运算符重载重定义等 函数在代码区函数名就是这个函数在代码区的地址这个地址就是这个函数的地址 4.2 动态多态(晚绑定,动态联编)
概念: 在运行阶段确定程序入口地址 又名: 动态联编晚绑定 如: 虚函数重写
5. 引入
要求设计一个函数根据传入的对象调用重写的方式。
5.1 示例
需求
小明开了一个宠物医院,可以给狗看病,可以给猫看病可以给猪看病张女士带着他家的狗旺财去找小明给狗看病李女士带着他家的猫布丁去找小明给猫看病王先生带着他家的猪佩奇去找小明给猪看病分析:对象小明张女士李女士王先生旺财布丁佩奇类动物类属性:姓名狗类猫类猪类人类属性:动物get与set宠物医生类看病代码
#include iostream
#include cstring
using namespace std;class Anim{
private:char name[50];
public:Anim(){}Anim(char *name){strcpy(this-name,name);}char* getName(){return name;}void setName(char *name){strcpy(this-name,name);}void call(){cout 动物叫 endl;}
};
class Dog:public Anim
{
public:Dog(){}Dog(char *name):Anim(name){}//重写父类call方法void call(){cout this-getName() :汪汪汪 endl;}
};
class Cat:public Anim
{
public:Cat(){}Cat(char *name):Anim(name){}//重写父类call方法void call(){cout this-getName() :喵喵喵 endl;}
};
class Pig:public Anim
{
public:Pig(){}Pig(char *name):Anim(name){}//重写父类call方法void call(){cout this-getName() :哼哼哼 endl;}
};
class Person:public Anim
{
private:Anim* anim;
public:Person(){anim NULL;}Person(char *name):Anim(name){}Person(char *name,Anim *anim):Anim(name),anim(anim){}~Person(){if(anim ! NULL){delete anim;anim NULL;}}void setAnim(Anim* anim){this-anim anim;}Anim* getAnim(){return anim;}//重写父类call方法void call(){cout this-getName() :哇哇哇 endl;}
};
class AnimDoctor:public Person{
public:AnimDoctor(){}AnimDoctor(char *name):Person(name){}AnimDoctor(char *name,Anim* anim):Person(name,anim){}void cb(Anim* anim){cout this-getName() 给 anim-getName() 看病 endl;anim-call();}
};
int main(int argc, char *argv[])
{Dog * dog new Dog(旺财);Cat * cat new Cat(布丁);Pig * pig new Pig(佩奇);Person *p1 new Person(张女士,dog);Person *p2 new Person(李女士,cat);Person *p3 new Person(王先生,pig);AnimDoctor * doctor new AnimDoctor(小明);doctor-cb(p1-getAnim());return 0;
}//小明给旺财看病
//动物叫
//小明给布丁看病
//动物叫
//小明给佩奇看病
//动物叫5.2 问题
父类有个函数 void call(){}要求是子类继承并重写 父类 该方法每个子类 动物在看病时都会叫 “狗汪汪汪猫喵喵喵…” ;
但是此时现状是每次打印出来的都是 父类 void call(){} 函数中 的 “动物叫”子传父 上行之后调用的依旧是父类的call函数而我们需要的是 子传父之后调用的是每个子类特有的方法。
所以需要引入 虚函数。
6. 虚函数
概念virtual 修饰的成员函数就是虚函数
语法
virtual 返回值类型 函数名(形参列表)
{函数体
}注意 子类在继承父类时会生成 虚函数指针 对比如下以上边动物看病为例 不是虚函数 虚函数下面第2幅图可以看出子类继承了父类的 name 和 虚函数指针 vfptr 此时指针指向的是 子类自己的 函数 Dog::call。 特点 当 子类转换为父类 后 使用该父类调用 使用virtual修饰的函数调用的是子类重写后的函数 使用该父类调用普通函数调用的是父类的该函数 6.1 上边示例修改
#include iostream
using namespace std;
#include cstring
class Anim{
private:char name[50];
public:Anim(){}Anim(char *name){strcpy(this-name,name);}char* getName(){return name;}void setName(char *name){strcpy(this-name,name);}virtual void call(){cout 动物叫 endl;}
};
class Dog:public Anim
{
public:Dog(){}Dog(char *name):Anim(name){}virtual void call(){cout this-getName() :汪汪汪 endl;}
};
class Cat:public Anim
{
public:Cat(){}Cat(char *name):Anim(name){}void call(){cout this-getName() :喵喵喵 endl;}
};
class Pig:public Anim
{
public:Pig(){}Pig(char *name):Anim(name){}void call(){cout this-getName() :哼哼哼 endl;}
};
class Person:public Anim
{
private:Anim* anim;
public:Person(){anim NULL;}Person(char *name):Anim(name){}Person(char *name,Anim *anim):Anim(name),anim(anim){}~Person(){if(anim ! NULL){delete anim;anim NULL;}}void setAnim(Anim* anim){this-anim anim;}Anim* getAnim(){return anim;}void call(){cout this-getName() :哇哇哇 endl;}
};
class AnimDoctor:public Person{
public:AnimDoctor(){}AnimDoctor(char *name):Person(name){}AnimDoctor(char *name,Anim* anim):Person(name,anim){}void cb(Anim* anim){cout this-getName() 给 anim-getName() 看病 endl;anim-call();}
};
int main(int argc, char *argv[])
{Dog * dog new Dog(旺财);Cat * cat new Cat(布丁);Pig * pig new Pig(佩奇);Person *p1 new Person(张女士,dog);Person *p2 new Person(李女士,cat);Person *p3 new Person(王先生,pig);AnimDoctor * doctor new AnimDoctor(小明);doctor-cb(p1-getAnim());doctor-cb(p2-getAnim());doctor-cb(p3-getAnim());/*当子类转换为父类后使用该父类调用使用virtual修饰的函数,调用的是子类重写后的函数使用该父类调用普通函数,调用的是父类的该函数*/// 虚函数所在的类,依据可以直接创建对象Anim a;return 0;
}
//小明给旺财看病
//旺财:汪汪汪
//小明给布丁看病
//布丁:喵喵喵
//小明给佩奇看病
//佩奇:哼哼哼6.2 动态绑定的条件(重要)
有继承子类重写父类的虚函数父类指针或引用指向子类空间(上行)。父类指针或引用才能调用子类重写的虚函数。错误演示:B b;//此时会调用父类的拷贝构造,会产生一个新的父类对象,该 父类对象a 与 子类对象b 是两个独立空间//所以此时使用a对象调用test01依据会执行父类的test01函数A a b; //拷贝构造a.test01();6.3 动态绑定原理(机制)(重要)
父类有虚函数产生的 虚函数指针 指向 虚函数表表中记录的是 父类的虚函数地址。如果子类继承 父类那么子类会继承父类的虚函数指针以及虚函数表。如果子类 重写父类的虚函数会将将虚函数表纪录的入口地址修改成子类重写的函数入口地址。这时 父类指针指向子类空间父类指针调用虚函数就 间接 调用子类重写的虚函数。
7. 纯虚函数
概念父类的虚函数没有函数体
语法
virtual 返回值类型 函数名(形参列表) 0;注意 纯虚函数所在的类不能 直接 创建对象这种类被称为抽象类子类继承与抽象类要么重写父类提供的所有纯虚函数要么自己也是抽象类 示例
#include iostream
#include cstring
using namespace std;
//纯虚函数所在的类称为抽象类
/*特点:* 1,抽象类不能直接创建对象* 2,子类继承与抽象类,要么重写所有纯虚函数,要么自己也是抽象类*/
class Anim{
private:char name[50];
public:Anim(){}Anim(char *name){strcpy(this-name,name);}char* getName(){return name;}void setName(char *name){strcpy(this-name,name);}//纯虚函数virtual void call() 0;virtual void sleep() 0;
};
class Dog:public Anim{
public:Dog(){}Dog(char *name):Anim(name){}void call(){cout 汪汪汪 endl;}
};
class Cat:public Anim{
public:Cat(){}Cat(char *name):Anim(name){}void call(){cout 喵喵喵 endl;}void sleep(){cout 在猫窝睡 endl;}
};
int main(int argc, char *argv[])
{//有纯虚函数所在的类为抽象类,抽象类不能直接创建对象//Anim anim//子类继承与抽象类,要么重写所有纯虚函数,要么自己也是抽象类//Dog类只重写了call纯虚函数,但是没有重写sleep纯虚函数//所以Dog类也是抽象类,所以不能直接创建对象//Dog dog;//Cat类重写了Anim类所有的纯虚函数,所以Cat类不是抽象类Cat cat;Anim anim cat;cout Hello World! endl;return 0;
}8. 虚析构造
8.1 问题引入
#include iostreamusing namespace std;
class Anim{
public:Anim(){cout 父类构造函数 endl;}~Anim(){cout 父类析构函数 endl;}
};class Dog:public Anim{
public:Dog(){cout 子类构造函数 endl;}~Dog(){cout 子类析构函数 endl;}
};
int main(int argc, char *argv[])
{Dog *dog new Dog();Anim *anim dog;delete anim;return 0;
}
//父类构造函数
//子类构造函数
//父类析构函数问题没有调用 子类析构函数
8.2 解决方案
将父类的析构函数 设置成 虚析构
虚析构函数是为了解决基类的指针指向派生类对象并用基类的指针删除派生类对象。
语法
virtual ~析构函数()
{}示例
#include iostreamusing namespace std;
class Anim{
public:Anim(){cout 父类构造函数 endl;}//虚析构virtual ~Anim(){cout 父类析构函数 endl;}
};class Dog:public Anim{
public:Dog(){cout 子类构造函数 endl;}~Dog(){cout 子类析构函数 endl;}
};
int main(int argc, char *argv[])
{Dog *dog new Dog();Anim *anim dog;delete anim;return 0;
}
//父类构造函数
//子类构造函数
//子类析构函数
//父类析构函数9. 纯虚析构(了解)
效果等同于 虚析构
语法
virtual 析构函数名() 0;注意需要在类外实现析构函数
示例
#include iostreamusing namespace std;
//class Anim{
//public:
// Anim()
// {
// cout 父类构造函数 endl;
// }
// //虚析构
// virtual ~Anim(){
// cout 父类析构函数 endl;
// }
//};
class Anim{
public:Anim(){cout 父类构造函数 endl;}//纯虚析构//类中定义virtual ~Anim() 0;
};
//类外实现
Anim::~Anim()
{cout 父类析构函数 endl;
}
class Dog:public Anim{
public:Dog(){cout 子类构造函数 endl;}~Dog(){cout 子类析构函数 endl;}
};
int main(int argc, char *argv[])
{Dog *dog new Dog();Anim *anim dog;delete anim;return 0;
}virtual 析构函数名() 0;注意需要在类外实现析构函数
示例
#include iostreamusing namespace std;
//class Anim{
//public:
// Anim()
// {
// cout 父类构造函数 endl;
// }
// //虚析构
// virtual ~Anim(){
// cout 父类析构函数 endl;
// }
//};
class Anim{
public:Anim(){cout 父类构造函数 endl;}//纯虚析构//类中定义virtual ~Anim() 0;
};
//类外实现
Anim::~Anim()
{cout 父类析构函数 endl;
}
class Dog:public Anim{
public:Dog(){cout 子类构造函数 endl;}~Dog(){cout 子类析构函数 endl;}
};
int main(int argc, char *argv[])
{Dog *dog new Dog();Anim *anim dog;delete anim;return 0;
}