zoukankan      html  css  js  c++  java
  • 学习:类和对象——多态和纯虚和抽象类等

    多态的基本概念:

    多态是C++面向对象三大特性之一

    多态分为两类

    1、静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名 ,那么这个我们之前都有用到过
    2、动态多态: 派生类和虚函数实现运行时多态

    静态多态和动态多态区别:

    1、静态多态的函数地址早绑定 - 编译阶段确定函数地址

    2、动态多态的函数地址晚绑定 - 运行阶段确定函数地址

    示例代码:

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class Animal {
    public:
    
    	virtual void speak() { // 进行virtual修饰成员函数,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
    		cout << "动物在说话" << endl;
    	}
    };
    
    class Dog :public Animal{
    public:
    	void speak() {
    		cout << "小狗在说话" << endl;
    	}
    
    };
    
    class Cat :public Animal {
    public:
    	void speak() {
    		cout << "小猫在说话" << endl;
    	}
    };
    
    void aaa(Animal & animal) {
    	animal.speak();
    }
    
    void test01() {
    	Cat c1;
    	aaa(c1);
    	Dog d1;
    	aaa(d1);
    	
    }
    
    int main() {
    	test01();
    	system("pause");
    	return 0;
    }
    

    总结:

    多态满足的条件:

    1、有继承关系
    2、子类重写父类中的虚函数

    多态使用条件:

    1、父类指针或引用指向子类对象

    重写:函数返回值类型 函数名 参数列表 完全一致称为重写


    多态的原理:

    不理解原理的话,真的很难受

    我们先来了解下一个虚函数虚拟指针虚拟表的概念:

    虚函数:当函数被virtual修饰过后,这个函数也就会被称为虚函数

    虚拟指针::当成为了虚函数,就会生成一个虚拟指针,这个指针保存的地址就是虚拟表的位置

    我们通过之前的工具来查看下类的构造

    正常的Cat类

    那么继承的是来自父类中的一切

    我们接着看下父类加了virtual之后的Cat类

    这时候的虚拟指针就指向虚拟表中的Cat类中speak函数的地址


    纯虚函数和抽象类:

    在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,所以我们在父类中的虚函数中定义的内容都没啥用

    因此可以将虚函数改为纯虚函数

    纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;

    当类中有了纯虚函数,这个类也称为抽象类

    抽象类特点:

    1、无法实例化对象
    2、子类必须重写抽象类中的纯虚函数,否则也属于抽象类

    示例代码:

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class Base {
    public:
    
    	virtual void to_take() = 0; //定义了一个纯虚函数to_take
    
    };
    
    class Son :public Base {
    public:
    
    	void to_take() {
    		cout << "这是实现了父类的to_take";
    	}
    
    };
    
    class Son2 :public Base {
    
    };
    
    int main() {
    
    	//Base b1; //直接实例化错误,因为Base为抽象类,为什么呢? 因为Base中用virtual定义了纯虚函数
    	//Son2 s2; //直接实例化错误,就算继承了Base但是没有实现to_take的纯虚函数,这个类还是一个抽象类,不是实体类
    
    	//以上的两个都是在栈区进行实例化的,那我们如果通过堆区实例化可以吗
    	//b1 = new Base; //答案是一样的,不可以
     
    
    	Base * base = new Son; //实例化成功,因为实现了父类中的纯虚函数
    	base->to_take(); //这里由于是指针,所以我们通过->来进行调用
    
    
    
    
    	system("pause");
    	return 0;
    }
    

    虚析构和纯虚析构:

    多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

    解决方式:将父类中的析构函数改为虚析构或者纯虚析构

    虚析构和纯虚析构共性:

    1、可以解决父类指针释放子类对象
    2、都需要有具体的函数实现

    虚析构和纯虚析构区别:

    如果是纯虚析构,该类属于抽象类,无法实例化对象

    虚析构语法:

    virtual ~类名(){}

    纯虚析构语法:

    virtual ~类名() = 0;

    类名::~类名(){}

    示例代码:解决方法两种

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class A {
    public:
    	virtual void speak() = 0; //纯虚函数
    
    	A() {
    		cout << "这是A的构造函数" << endl;
    	}
    	//virtual ~A() { //利用虚析构可以解决父类指针释放子类对象时候不干净的问题
    	//	cout << "这是A的析构函数" << endl;
    	//}
    
    	virtual ~A() = 0; //利用纯虚析构来解决父类指针释放子类对象时候不干净的问题,在全局实现A的析构函数
    };
    
    A::~A() {
    	cout << "这是A的析构函数" << endl;
    }
    
    class B:public A {
    public:
    	B(int age) {
    		cout << "这是B的构造函数" << endl;
    		this->age = new int(age);
    
    	}
    	~B() {
    		if (age != NULL) {
    			delete age;
    			age = NULL;
    			cout << "这是B的析构函数" << endl;
    		}
    	}
    
    	virtual void speak() {
    		cout << "年龄为"<< *this->age << "岁的B在说话" << endl;
    	}
    
    	
    public:
    	int * age; //定义一个指针变量,来储存堆区的数据
    
    };
    
    void test01() {
    	A * a = new B(100);
    	a->speak();
    	delete a; //进行释放 调用相应的父类的析构函数 但是不会走子类的析构函数
    
    
    }
    
    int main() {
    	test01();
    	system("pause");
    	return 0;
    }
    

    总结:

    1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

    2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构

    3. 拥有纯虚析构函数的类也属于抽象类

  • 相关阅读:
    [BZOJ-1007&洛谷P3194][HNOI2008]水平可见直线--【半平面交(单调栈)】
    [BZOJ-1006&洛谷P3196][HNOI2008]神奇的国度--【图的染色-最大势MCS算法】
    [BZOJ-1005&洛谷P2624][HNOI2008]明明的烦恼-【Purfer序列】py+java
    [BZOJ1211 & 洛谷P2290] [HNOI2004]树的计数-【Purfer序列】py+Java
    【BZOJ-1004&洛谷P1446】[HNOI2008]Cards-置换群(burnside引理|DP)
    POJ-2409 Let it Bead 【置换群-Polya定理】
    Dijkstra--POJ 2502 Subway(求出所有路径再求最短路径)
    二分--LIGHTOJ 1088查找区间(水题)
    二分--1043
    二分---LIGHTOJ 1062
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/11870079.html
Copyright © 2011-2022 走看看