Day8 知识点:
1.赋值兼容
赋值兼容只能发生在公有派生继承的父子关系中。
a) 子类对象(派生类)赋给父类(基类)的对象
b) 子类对象赋给父类的引用
c) 子类对象的地址赋给父类的指针
实验代码:
#include <iostream>
using namespace std;
class shape
{
public:
shape(int x = 0, int y = 0)
:_x(x),_y(y){}
void draw()
{
cout<<"drawfrom"<<"("<<_x<<","<<_y<<")"<<endl;
}
protected:
int _x;
int _y;
};
class circle:public shape
{
public:
circle(int x = 0, int y = 0, int r = 0)
:shape(x,y),_radius(r){}
void draw()
{
cout<<"drawfrom"<<"("<<_x<<","<<_y<<")";
cout<<" radius = "<<_radius<<endl;
}
void func()
{
cout<<"------------------"<<endl;
}
private:
int _radius;
};
int main()
{
shape s(1,2);
s.draw();
circle c(1,2,3);
c.draw();
c.func();
shape s1 = c; //派生类对象赋给基类对象
s1.draw();
shape &rc = c; //派生类对象赋给基类的引用
rc.draw();
shape *pc = &c; //派生类对象的地址赋给指向基类的指针
pc->draw();
return 0;
}
2.多态:由继承产生的相关的不同的类,对同一消息做出的不同响应。
静多态,编译阶段决定的
#include <iostream>
using namespace std;
void func(int a, float b)
{
cout<<"void func(int a, float b)"<<endl;
}
void func(float a, int b)
{
cout<<"void func(float a, int b)"<<endl;
}
int main()
{
func(1,3.0); //在编译阶段就完成函数的倾轧
func(3.0,1);
return 0;
}
动多态,运行阶段决定的
实现条件:
1) 父类中有虚函数(在函数声明前加virtual,定义时不需要)
2) 子类中覆写(override)了父的虚函数,根据需要重新定义函数体
{
a) overload重载 同一作用域中,函数名相同,参数列表不同;
b) shadow 发生在父子类中的同名成员(函数或数据,如果是函数只要同名就会构成shadow);
c) override 发生在父子类中,父类中函数有virtual声明的函数,子类中同参,同名,同返回。
}
3) 成员函数被声明为虚函数后,其子类中的完全相同的函数也是虚函数。可以加virtual以示清晰(也可不加)
4) 定义一个父类的指针,将子类对象地址赋给父类的指针,通过该指针调用虚函数,调用的就是所指向子类中的虚函数
5) 子类中覆写的函数可以是任意访问类型,依需求而定。
实验代码:
#include <iostream>
using namespace std;
class shape
{
public:
shape(int x = 0, int y = 0)
:_x(x),_y(y){}
virtual void draw()
{
cout<<"drawfrom"<<"("<<_x<<","<<_y<<")"<<endl;
}
protected:
int _x;
int _y;
};
class Circle:public shape
{
public:
Circle(int x = 0, int y= 0, int r = 0)
:shape(x,y),_radius(r){}
virtual void draw()
{
cout<<"drawfrom"<<"("<<_x<<","<<_y<<")";
cout<<" _radius ="<<_radius<<endl;
}
private:
int _radius;
};
class Rec:public shape
{
public:
Rec(int x = 0, int y = 0,int len = 0, int wid = 0 )
:shape(x,y),_len(len),_wid(wid){}
virtual void draw()
{
cout<<"drawfrom"<<"("<<_x<<","<<_y<<")";
cout<<" _len ="<<_len<<" _wid= "<<_wid<<endl;
}
private:
int _len;
int _wid;
};
int main()
{
Circle c(1,2,3);
c.draw();
Rec r(1,2,3,4);
r.draw();
shape *ps = NULL;
int choice;
while(1)
{
scanf("%d",&choice);
switch(choice)
{
case 1:
ps = &c;
ps->draw();
break;
case 2:
ps = &r;
ps->draw();
break;
}
}
return 0;
}
3.
virtual void draw() = 0;纯虚函数格式
1.含有纯虚函数的类,称为抽象基类,不可实列化。即不能创建对象,存在的意义就是被
继承,提供族类的公共接口,java 中称为 interface;
2. 纯虚函数只有声明,没有实现,被“初始化”为 0;
3. 如果一个类中声明了纯虚函数,而在派生类中没有对该函数定义,则该虚函数在派生类
中仍然为纯虚函数,派生类仍然为纯虚基类。
#include <iostream>
using namespace std;
class shape
{
public:
shape(int x = 0, int y = 0)
:_x(x),_y(y){}
virtual void draw() = 0;
protected:
int _x;
int _y;
};
class Circle:public shape
{
public:
Circle(int x = 0, int y= 0, int r = 0)
:shape(x,y),_radius(r){}
virtual void draw()
{
cout<<"drawfrom"<<"("<<_x<<","<<_y<<")";
cout<<" _radius ="<<_radius<<endl;
}
private:
int _radius;
};
class Rec:public shape
{
public:
Rec(int x = 0, int y = 0,int len = 0, int wid = 0 )
:shape(x,y),_len(len),_wid(wid){}
virtual void draw()
{
cout<<"drawfrom"<<"("<<_x<<","<<_y<<")";
cout<<" _len ="<<_len<<" _wid= "<<_wid<<endl;
}
private:
int _len;
int _wid;
};
int main()
{
Circle c(1,2,3);
Rec r(3,4,5,6);
shape *ps = &c;
ps->draw();
ps = &r;
ps->draw();
return 0;
}
4.虚析构(在析构器前加virtual)
目的:为了析构完全,在delete父类指针的时候,会调用子类的析构函数,实现完整析构。
使用方法:当一个类中有虚函数的时候,将其析构函数一并加上virtual
实验代码:
//animal.h
#ifndef ANIMAL_H
#define ANIMAL_H
class Animal
{
public:
Animal();
virtual ~Animal(); //如果不加virtual,在释放堆内存的时候只会对Animai进行析构,
virtual void voice() = 0; //Animal指针指向的内存不会自动完成析构
};
#endif // ANIMAL_H
//cat.h
#ifndef CAT_H
#define CAT_H
#include "animal.h"
class Cat:public Animal
{
public:
Cat();
~Cat();
virtual void voice();
};
#endif // CAT_H
//dog.h
#ifndef DOG_H
#define DOG_H
#include "animal.h"
class Dog:public Animal
{
public:
Dog();
~Dog();
void voice();
};
#endif // DOG_H
//animal.cpp
#include "animal.h"
#include <iostream>
using namespace std;
Animal::Animal()
{
cout<<"Animal()"<<endl;
}
Animal::~Animal()
{
cout<<"~Animal()"<<endl;
}
//cat.cpp
#include "cat.h"
#include <iostream>
using namespace std;
Cat::Cat()
{
cout<<"Cat()"<<endl;
}
Cat::~Cat()
{
cout<<"~Cat()"<<endl;
}
void Cat::voice()
{
cout<<"I am a cat,miao miao miao"<<endl;
}
//dog.cpp
#include "dog.h"
#include <iostream>
using namespace std;
Dog::Dog()
{
cout<<"Dog()"<<endl;
}
Dog::~Dog()
{
cout<<"~Dog()"<<endl;
}
void Dog::voice()
{
cout<<"I am a dog,wang wang wang"<<endl;
}
//main.cpp
#include <iostream>
#include "animal.h"
#include "cat.h"
#include "dog.h"
using namespace std;
int main()
{
Dog d;
Cat c;
Animal *a1 = &d;
Animal *a2 = &c;
a1->voice();
a2->voice();
Animal *a = new Dog;
delete a;
return 0;
}
5.基于多态的依赖倒置设计原则
依赖倒置定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象
下面以两种不同的程序设计方法来表达设计思想
场景是这样的,母亲给孩子讲故事,只要给她一本书,她就可以照着书给孩子讲故事了。
传统过程设计:
#include <iostream>
using namespace std;
class Book
{
public:
string getContents()
{
return "A little bear are crying";
}
};
class News
{
public:
string getContents()
{
return "Mr.Zhou were awarded with the Noble Prize";
}
};
class Mother
{
public:
void tellContents(Book *b)
{
cout<<b->getContents()<<endl;
}
void tellContents(News *n)
{
cout<<n->getContents()<<endl;
}
};
int main()
{
Mother m;
Book b;
News n;
m.tellContents(&b);
m.tellContents(&n);
return 0;
}
#include <iostream>
using namespace std;
class Ireader
{
public:
virtual string getContents() = 0;
};
class Book:public Ireader
{
public:
virtual string getContents()
{
return "A little bear are crying";
}
};
class News:public Ireader
{
public:
virtual string getContents()
{
return "Mr.Zhou were awarded with the Noble Prize";
}
};
class Mother
{
public:
void tellContents(Ireader *i)
{
cout<<i->getContents()<<endl;
}
};
int main()
{
Mother m;
Book b;
News n;
m.tellContents(&b);
m.tellContents(&n);
return 0;
}
电脑组装实验代码:
#include <iostream>
using namespace std;
class CPU
{
public:
virtual void run() = 0;
};
class Mem
{
public:
virtual void run() = 0;
};
class Disk
{
public:
virtual void run() = 0;
};
class Intel:public CPU
{
public:
virtual void run()
{
cout<<"Intel CPU"<<endl;
}
};
class Kingston:public Mem
{
public:
virtual void run()
{
cout<<"Kingston Mem"<<endl;
}
};
class Wddisk:public Disk
{
public:
virtual void run()
{
cout<<"Wddisk"<<endl;
}
};
class Computer
{
public:
Computer(CPU *pc,Mem *pm,Disk *pd)
:_pc(pc),_pm(pm),_pd(pd){}
void work()
{
_pc->run();
_pm->run();
_pd->run();
}
~Computer()
{
delete _pc;
delete _pm;
delete _pd;
}
private:
CPU *_pc;
Mem *_pm;
Disk *_pd;
};
int main()
{
Computer c(new Intel,new Kingston,new Wddisk);
c.work();
return 0;
}