继承与多态(下)

重写与重载

重载和重写有什么区别?什么时候是重载,什么时候是重写?

#include <cstdlib>
#include <iostream>

using namespace std;

class Parent{
public:
	void func()	{
		cout << "void func()" <<endl;
	}
	virtual void func(int i){
		cout << "void func(int i)" <<endl;
	}
	virtual void func(int i, int j){
		cout << "void func(int i, int j)" <<endl;
	}

};

class Child : public Parent{
public:
	void func(int i, int j){
		cout << "void func(int i, int j)" <<" " <<i+j <<endl;
	}
	void func(int i, int j, int k) {
		cout << "void func(int i, int j, int k) " <<i+j+k  <<endl;
	}
};

int main(int argc, char *argv[])
{
    Parent p;
    p.func();
    p.func(1);
    p.func(1,2);
    
    
    Child c;
    c.func(); //error
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dG5QYgOp-1582529383157)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582515438000.png)]

完整代码:

#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
public:
    virtual void func()
    {
        cout<<"void func()"<<endl;
    }
    
    virtual void func(int i)
    {
        cout<<"void func(int i)"<<endl;
    }
    
    virtual void func(int i, int j)
    {
        cout<<"void func(int i, int j)"<<endl;
    }
};

class Child : public Parent
{
public:
    void func(int i, int j)
    {
        cout<<"void func(int i, int j)"<<" "<<i + j<<endl;
    }
    
    void func(int i, int j, int k)
    {
        cout<<"void func(int i, int j, int k)"<<" "<<i + j + k<<endl;
    }
};

void run(Parent* p) //验证: Parent::func(int i, int j)与Child::func(int i, int j) 是否为重写 
{
    p->func(1, 2);
}

int main(int argc, char *argv[])
{
    Parent p;    
    p.func();
    p.func(1);
    p.func(1, 2);
    
    cout<<"\n"<<endl;
    
    Child c;    
//    c.func(); //重载只能发生在同一个类中(即:同一个作用域中) 
    
    run(&p);
    run(&c);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gk0A0aCe-1582529383160)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582516034438.png)]

重载与重写的区别

函数重载
必须在同一个类中进行
子类无法重载父类的函数,父类同名函数将被覆盖(上例:c.func(); //error)
重载是在编译期间根据参数类型和个数决定调用函数
函数重写
必须发生于父类与子类之间
并且父类与子类中的函数必须有完全相同的原型
使用virtual声明之后能够产生多态
多态是在运行期间根据具体对象的类型决定调用函数

tips:

重载比重写的效率要高;

虚函数深入理解

问题:是否可以将类的每个成员函数都声明为虚函数?

C++中多态的实现原理
当类中声明虚函数时,编译器会在类中生成一个虚函数表
虚函数表是一个存储类成员函数指针的数据结构
虚函数表是由编译器自动生成与维护的
virtual成员函数会被编译器放入虚函数表中
存在虚函数时,每个对象中都有一个指向虚函数表的指针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fog6SqvO-1582529383161)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582523539684.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Id5Oak0n-1582529383163)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582523636837.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F5KT90H2-1582529383164)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582523680474.png)]

问题:对象中的VPTR指针什么时候被初始化?

​ 对象在创建的时候由编译器对VPTR指针进行初始化
​ 只有当对象的构造完全结束后VPTR的指向才最终确定
​ 父类对象的VPTR指向父类虚函数表
​ 子类对象的VPTR指向子类虚函数表

结论:构造函数中调用虚函数无法实现多态。

代码实例:构造函数中的“多态”(无法实现)

#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
public:
    Parent()
    {
        this->func(); //此处会调用Parent::func()  构造函数中调用虚函数无法实现多态。
    }
    
    virtual void func()
    {
        cout<<"void Parent::func()"<<endl;
    }
};

class Child : public Parent
{
public: 
    void func()
    {
        cout<<"void Child::func()"<<endl;
    }
};

int main(int argc, char *argv[])
{
    Child c;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-137zPQgA-1582529383165)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582525663749.png)]

纯虚函数

面向对象中的抽象概念

​ 在进行面向对象分析时,会有一些抽象的概念!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TtgPqzus-1582529383167)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582526149408.png)]

​ 考虑如何给图形求面积?

在现实中需要知道具体的图形类型才能求面积,所以对概念上的“图形”求面积是没有意义的!

class Shape{
public:    
    double area(){
        return 0; //“图形”的面积为0,合适吗?
    }
};

分析:这个类的设计完全脱离实际,没有任何的意义!

Shape类的不合理

#include <cstdlib>
#include <iostream>

using namespace std;

//图形 
class Shape{
public:	
	virtual double area(){
		return 0;
	}
};
//矩形 
class Rectangle : public Shape{
	double m_a;
	double m_b;
	
public:
	Rectangle(double a, double b){
		m_a = a;
		m_b = b;
	}
	
	double area(){
		return m_a*m_b;
	}
};
//圆
class Circle : public Shape {
	double m_r;
public:
	Circle(double r){
		m_r = r;
	}
	double area(){
		return 3.14*m_r*m_r;
	}
};

//求图形的面积 
void area(Shape* s){
	cout << s->area() <<endl;
}

int main(int argc, char *argv[])
{
    Rectangle rect(2,3);
    Circle circle(4);
    Shape s;
    
    area(&rect);
    area(&circle);
    area(&s); //Shape面积为0,不合理 
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-idP0ZohL-1582529383169)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582528564874.png)]

面向对象中的抽象类
抽象类可用于表示现实世界中的抽象概念
抽象类是一种只能定义类型,而不能产生对象的类
抽象类只能被继承并重写相关函数
抽象类的直接特征是纯虚函数

纯虚函数是只声明函数原型,而故意不定义函数体的虚函数。

抽象类与纯虚函数
抽象类不能用于定义对象
抽象类只能用于定义指针和引用
抽象中的纯虚函数必须被子类重写

class Shape{
public:
	virtual double area() = 0;
}

area是纯虚函数,= 0 告诉编译器,这个函数故意只声明不定义。

完整代码

#include <cstdlib>
#include <iostream>

using namespace std;

//图形 
class Shape{
public:	
	virtual double area() = 0; //纯虚函数 
};
//矩形 
class Rectangle : public Shape{
	double m_a;
	double m_b;
	
public:
	Rectangle(double a, double b){
		m_a = a;
		m_b = b;
	}
	
	double area(){
		return m_a*m_b;
	}
};
//圆
class Circle : public Shape {
	double m_r;
public:
	Circle(double r){
		m_r = r;
	}
	double area(){
		return 3.14*m_r*m_r;
	}
};

//求图形的面积 
void area(Shape* s){ //可以定义抽象类的指针 
	cout << s->area() <<endl;
}

int main(int argc, char *argv[])
{
    Rectangle rect(2,3);
    Circle circle(4);
//    Shape s; //error 
    
    area(&rect);
    area(&circle);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-joJawQNY-1582529383170)(E:\md文件资源%5CUsers%5CWGJ%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1582529284058.png)]

小结

函数重载与函数重写不同
多态是通过虚函数表实现的
虚函数在效率上会受到影响
抽象类可用于表示现实世界中的抽象概念
抽象类是通过纯虚函数实现的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值