精华内容
下载资源
问答
  • 多态的实现方式
    万次阅读
    2018-08-10 09:35:44

    1.普通类

     AnimalFu a =  new AnimalZi new();

    2.抽象类 animal  是父类抽象类

    Animal a = new Cat();

    3.接口 // 学生是类  smoking  是接口 

    Smoking sk = new Student() 

    多态的特点:

    变量:编译看父类

    方法:运行看子类

    更多相关内容
  • C++多态实现方式详情

    2022-04-10 13:36:25
    更多python、PHP、JAVA... 到此这篇关于C++多态实现方式详情的文章就介绍到这了,更多相关C++多态内容请搜索菜鸟教程www.piaodoo.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持菜鸟教程www.piaodoo.com!

    更多python、PHP、JAVA、C、C++教程请到友情连接: 菜鸟教程https://www.piaodoo.com

    茂名一技http://www.enechn.com

    ppt制作教程步骤 http://www.tpyjn.cn

    兴化论坛http://www.yimoge.cn

    电白论坛 http://www.fcdzs.com

    表格制作excel教程 http://www.tsgmyy.cn


    学习通 http://www.hssi.net/


    :文章转自公众号:Coder梁(ID:Coder_LT)

    在我们之前介绍的继承的情况当中,派生类调用基类的方法都是不做任何改动的调用。

    但有的时候会有一些特殊的情况,我们会希望同一个方法在不同的派生类当中的行为是不同的。举个简单的例子,比如speak方法,在不同的类当中的实现肯定是不同的。如果是Human类,就是正常的说话,如果是Dog类可能是汪汪,而Cat类则是喵喵。

    在这种情况下只是简单地使用继承是无法满足我们的要求的,最好能够有一个机制可以让方法有多种形态,不同的对象去调用的逻辑不同。这样的行为称为多态。

    这里稍微强调一下,多态是一种面向对象的设计思路,本身和C++不是强绑定的,其他语言当中一样有多态,只不过实现的方式可能有所不同。

    在C++当中有两种重要的机制用于实现多态:

    • 在派生类当中重新定义基类的方法
    • 使用虚方法

    我们来看一个例子:

    class Mammal {
    ?private:
    ? string name;
    ?public:
    ? Mammal(string n): name(n) {}
    ? ? ?string Name() const{
    ? ? ? ? ? ? return name;
    ? ? ? ? }
    ? virtual void speak() const {
    ? ?cout << "can't say anything" << endl;
    ? }
    ? ? ?virtual ~Mammal() {};
    };
    

    class Human : public Mammal{
    ?private:
    ? string job;
    ?public:
    ? Human(string n, string j): Mammal(n), job(j) {}
    ? virtual void speak() const {
    ? ?cout << “i’m human” << endl;
    ? }
    };

    由于示例比较简单,所以我们把类的声明和实现写在一起了。

    从结构上来看,这就是一个简单的继承,我们实现了两个类,一个叫做Mammal,一个叫做Human,然后给它们各自定义了一些成员变量。

    值得注意的是speak函数,我们在函数声明前面加上了一个关键字virtual,这表示这是一个虚函数。

    方法被定义成虚方法之后,在程序执行的时候,将会根据派生类的类型来选择执行的方法版本。在进行调用的时候,程序是根据对象类型而不是引用和指针的类型来选择执行的方法,

    如:

    Mammal *m = new Human("man", "spiderman");
    m->speak();

    这里我们用一个Mammal的指针指向了一个Human类型的对象,当我们调用方法的时候,由于speak方法是一个虚方法。因此执行的时候程序会根据对象的类型也就是Human去执行Human对象中的speak方法,而不是Mammal中的。

    通常我们会将析构函数也设置成虚方法,因为派生类当中往往有一些专属成员,这是一种惯例。因为如果析构函数不是虚函数,那么只会调用对应指针类型的析构函数,这意味着可能在一些情况下产生错误和问题。

    在上述的示例当中,我们是将类方法的实现和声明写在一起了,如果还是采取和之前一样分开实现的方式,需要注意我们无需在函数签名中加上virtual关键字。

    到此这篇关于C++多态实现方式详情的文章就介绍到这了,更多相关C++多态内容请搜索菜鸟教程www.piaodoo.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持菜鸟教程www.piaodoo.com!

    展开全文
  • java基础:多态实现方式 很多地方都写着多态三要素是: 继承、重写、向上转型。 所以继承实现多态我理解了,那么用接口实现多态的呢,它并不符合多态三要素。很困惑,希望大佬来解答一下!
  • C++多态三种实现方式

    千次阅读 2020-10-14 19:52:01
    多态实现方式分为三块:重载、重写、重定义。下面我们来谈一谈他们各自的实现方式和实现原理。 重载 实现方式 重载是在同一作用域内(不管是模块内还是类内,只要是在同一作用域内),具有相同函数名,不同的形参...

    定义
    多态的定义简单来说就是使一条语句有多种状态。

    实现方式
    多态的实现方式分为三块:重载、重写、重定义。下面我们来谈一谈他们各自的实现方式和实现原理。

    重载
    实现方式
    重载是在同一作用域内(不管是模块内还是类内,只要是在同一作用域内),具有相同函数名,不同的形参个数或者形参类型。返回值可以相同也可以不同(在函数名、形参个数、形参类型都相同而返回值类型不同的情况下无法构成重载,编译器报错。这个道理很简单,在函数调用的时候是不看返回值类型的)。

    实现原理
    重载是一种静态多态,即在编译的时候确定的。C++实现重载的方式是跟编译器有关,编译过后C++的函数名会发生改变,会带有形参个数、类型以及返回值类型的信息(虽然带有返回值类型但是返回值类型不能区分这个函数),所以编译器能够区分具有不同形参个数或者类型以及相同函数名的函数。插一句,在C语言中编译器编译过后函数名中不会带有形参个数以及类型的信息,因此C语言没有重载的特性。由此带来麻烦的一点是如果想要在C++中调用C语言的库,需要特殊的操作(extern “C”{})。库中的函数经过C编译器编译的话会生成不带有形参信息的函数名,而用C++的编译器编译过后会生成带有形参信息的函数名,因此将会找不到这个函数。extern “C”{}的作用是使在这个作用域中的语句用C编译器编译,这样就不会出错。这也是一种语言兼容性的问题。

    重写
    实现方式
    重写是在不同作用域内(一个在父类一个在子类),函数名、形参个数、形参类型、返回值类型都相同并且父类中带有virtual关键字(换言之子类中带不带virtual都没有关系)。有一种特殊的情况:函数返回值类型可以不同但是必须是指针或者引用,并且两个虚函数的返回值之间必须要构成父子类关系。这种情况称之为协变,也是一种重写。引入协变的好处是为了避免危险的类型转换。

    实现原理
    重写是一种动态多态,即在运行时确定的。C++实现重写的方式也跟编译器有关,编译器在实例化一个具有虚函数的类时会生成一个vptr指针(这就是为什么静态函数、友元函数不能声明为虚函数,因为它们不实例化也可以调用,而虚函数必须要实例化,这也是为什么构造函数不能声明为虚函数,因为你要调用虚函数必须得要有vptr指针,而构造函数此时还没有被调用,内存中还不存在vptr指针,逻辑上矛盾了)。vptr指针在类的内存空间中占最低地址的四字节。vptr指针指向的空间称为虚函数表,vptr指针指向其表头,在虚函数表里面按声明顺序存放了虚函数的函数指针,如果在子类中重写了,在子类的内存空间中也会产生一个vptr指针,同时会把父类的虚函数表copy一下当做自己的,然后如果在子类中重新声明了虚函数,会按声明顺序接在父类的虚函数函数指针下。而子类中重写的虚函数则会替换掉虚函数表中原先父类的虚函数函数指针。重点来了,在调用虚函数时,不管调用他的是父类的指针、引用还是子类的指针、引用,他都不管,只看他所指向或者引用的对象的类型(这也称为动态联编),如果是父类的对象,那就调用父类里面的vptr指针然后找到相应的虚函数,如果是子类的对象,那就调用子类里面的vptr指针然后找到相应的虚函数。当然这样子的过程相比静态多态而言,时间和空间上的开销都多了(这也是为什么内联函数为什么不能声明为虚函数,因为这和内联函数加快执行速度的初衷相矛盾)。

    重定义
    实现方式
    重定义是在不同作用域内的(一个在父类一个在子类),只要函数名相同,且不构成重写,均称之为重定义

    实现原理
    重定义的实现原理跟继承树中函数的寻找方式有关,他会从当前对象的类作用域内开始查找同名的函数,如果没有找到就一直向上查找直到基类为止。如果找到一个同名的函数就停止。这也就说明他不管函数的形参类型或者个数是不是一样,只要函数名一样,他就认为是找到了,如果这时候形参类型或者个数不一致,编译器就会报错。多重继承的查找,如果在同一层内出现一样的函数声明那么编译器会报错不知道调用哪一个函数,这类问题也叫钻石继承问题。钻石问题的解决方案可以通过虚继承来实现,这样就不会存在多个一样的函数声明。

    展开全文
  • C++多态实现

    2022-05-17 22:47:09
    本篇文章主要介绍了C++虚函数、动态析构、纯虚函数与抽象类的实现


    前言

    本篇文章主要介绍了C++虚函数、动态析构、纯虚函数与抽象类的实现


    1.多态的概念

    多态的本质: 形式上,使用统一的父类指针做一般性处理, 但是实际执行时,这个指针可能指向子类对象, 形式上,原本调用父类的方法,但是实际上会调用子类的同名方法。

    2.虚函数

    C++通过虚函数(在成员函数前加virtual关键字,在子类中重载该函数)来实现多态。
    多态的本质:
    形式上,使用统一的父类指针做一般性处理,但是实际执行时,这个指针可能指向子类对象,
    形式上,原本调用父类的方法,但是实际上会调用子类的同名方法。

    2.1 虚函数的使用

    虚函数的定义:
    在函数的返回类型之前使用virtual
    只需要在成员函数的声明中添加virtual
    虚函数的继承:
    1. 如果某个成员函数被声明为虚函数,那么它的子类【派生类】,以及子类的子类中,所继承的这个成员函数,也自动是虚函数。
    2. 如果在子类中重写这个虚函数,可以不用再写virtual, 但是仍建议写virtual, 更可读。(或者在声明时加 override 或 final)
    3. final 关键字禁止子类重写该函数(声明时使用即可)。
    4. override 表示该函数是从父类继承的,增加可读性(声明时使用即可)。

    #include <iostream>
    using namespace std;
    class Person{
    public:
        virtual void print(const char *word){
            cout << "person:" << word << endl;
        }
    };
    
    class Father:public Person{
    public:
        void print(const char *word) override{
            cout << "father:" << word << endl;
        }
    };
    
    class Son:public Father{
    public:
        void print(const char *word) final{
            cout << "son:" << word << endl;
        }
    };
    
    
    void say(Person *peo, const char *word){
        peo->print(word);
    }
    //void say(Person &peo, const char *word){
    //    peo.print(word);
    //}
    int main() {
        Father f1;
        Son s1;
    
        say(&f1,"playing games?");
        say(&s1,"no,I'm learning");
    
        // say(f1,"playing games?");
        // say(s1,"no,I'm learning");
    
        return  0;
    }
    
    

    2.2 虚函数表的概念

    1. 存在虚函数的类都有一个一维的虚函数表叫做虚表。当类中声明虚函数时,编译器会自动在类中生成一个虚函数表。
    2.类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。
    3.虚函数表是一个存储类成员函数指针的数据结构。
    4.virtual成员函数会被编译器放入虚函数表中。
    5.当存在虚函数时,每个对象中都有一个指向虚函数表的指针(C++编译器给父类对象,子类对象提前布局vptr指针),当进行test(father *base)函数的时候,C++编译器不需要区分子类或者父类对象,只需要再base指针中,找到vptr指针即可)。
    6. vptr一般作为类对象的第一个成员。

    使用继承的虚函数表构建过程:
    1.直接复制父类的虚函数表;
    2.如果子类重写了某个虚函数,那么就在这个虚函数表中进行相应的替换;
    3.如果子类增加了新的虚函数,就把这个虚函数添加到虚函数表中
    如果继承了多个父类(会继承多个虚函数表),如果第一个父类有其他数据成员(存放在栈中),那么第二个虚函数表会排在父类所有成员的后面,子类新加的虚函数放在第一个虚函数表中。

    #include <iostream>
    
    using namespace std;
    
    class Person {
    
    public:
    	virtual void fun1() {
    		cout << __FUNCTION__ << endl;
    	}
    	virtual void fun2() {
    		cout << __FUNCTION__ << endl;
    	}
    };
    
    class Father : public Person {
    public:
    	void fun1() override {
    		cout << __FUNCTION__ << endl;
    	};
    	virtual void fun3(){
    		cout << __FUNCTION__ << endl;
    	}
    	int a = 10;
    };
    
    class Mather {
    public:
    	virtual void funMather() {
    		cout << __FUNCTION__ << endl;
    	}
    };
    
    class Son : public Father ,public Mather{
    public:
    	virtual void fun4() {
    		cout << __FUNCTION__ << endl;
    	}
    	void fun1() final {
    		cout << __FUNCTION__ << endl;
    	}
    	
    };
    
    
    typedef void (*fun)();//定义一个函数指针方便调用虚函数表里的函数
    
    
    int main(void) {
    
    	//含有虚函数的对象中,最先存储的就是"虚函数表"的地址(即对象名,就是虚函数表的地址)
    	Person peo;
    
    	/*
    		先拿到虚函数表的地址 将其转换为int类型指针(int *)&peo,
    		然后寻址找拿到虚函数表的首个函数地址 *(int *)&peo,
    		最后用int *vptr接收拿到的地址 int *vptr = (int *)*(int *)&peo(此时vptr指向的是虚函数表里的首个虚函数)。
    	*/
    	int *vptr = (int *)*(int *)&peo;
    
    	(fun (*(vptr + 0)))();
    	(fun (*(vptr + 1)))();
    
    	/*
    		使用继承的虚函数表构建过程:
    			1.直接复制父类的虚函数表;
    			2.如果子类重写了某个虚函数,那么就在这个虚函数表中进行相应的替换;
    			3.如果子类增加了新的虚函数,就把这个虚函数添加到虚函数表中
    		如果继承了多个父类(继承多张虚函数表),那么虚函数表按照继承的先后顺序排序(class Son : public Father, public Mather
    		先Father 后Mather)在对象的内存中排列。并且子类增加的虚函数会添加到第一个表中。
    	
    	*/
    	cout << "---------一条优雅的分割线-----------" << endl;
    
    	Son son;
    
    	vptr = (int *)*(int *)&son;
    
    	(fun (*(vptr + 0)))();
    	(fun (*(vptr + 1)))();
    	(fun (*(vptr + 2)))();
    	(fun (*(vptr + 3)))();
    
    	int *vptr2 = (int *)*((int *)&son + 2);// int 类型指针加2,拿到vptr2(第二张虚函数表的地址)
    	(fun(*vptr2 + 0))();
    
    
    	system("pause");
    	return 0;
    }
    

    vs分析类内内存分布(在项目属性的命令行选项中加/d1 reportSingleClassLayout类名):
    在这里插入图片描述
    虚函数表内存分布:


    2.3 虚析构函数(多态中的动态析构)

    为了防止内存泄露,最好是在基类析构函数上添加virtual关键字,使基类析构函数为虚函数
    目的在于,当使用delete释放基类指针时,会实现动态的析构:
    如果基类指针指向的是基类对象,那么只调用基类的析构函数
    如果基类指针指向的是子类对象,那么先调用子类的析构函数,再调用父类的析构函数

    #include <iostream>
    
    using namespace std;
    
    class Person {
    public:
    	Person(const char *name = "null") {
    		int len = strlen(name) + 1;
    		this->name = new char[len];
    		strcpy_s(this->name,len, name);
    	}
    
    	virtual ~Person() {
    		cout << "执行了Person析构函数" << endl;
    		if (this->name) {
    			delete this->name;
    			name = NULL;
    		}
    	}
    protected:
    	char *name;
    };
    
    class Student : public Person {
    public:
    	Student(const char *name="null", const char *addr="null") : Person(name) {
    		int len = strlen(addr) + 1;
    		this->addr = new char[len];
    		strcpy_s(this->addr,len, addr);
    	}
    	~Student() {
    		cout << "执行了Student析构函数" << endl;
    		if (this->addr) {
    			delete this->addr;
    			addr = NULL;
    		}
    	}
    private:
    	char *addr;
    };
    int main(void) {
    	Person *peo = new Person();
    	delete peo;
    	Student *stu = new Student();
    	delete stu;
    	peo = new Student();
    	//这里如果Person的析构函数不加virtual,\
    	在析构时只会执行Person的析构函数,从而造成内存泄漏
    	delete peo;
    	system("pause");
    	return 0;
    }
    

    3. 纯虚函数与抽象类

    1.C++ 接口是使用抽象类来实现的。
    2.如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。纯虚函数是通过在声明中使用 “= 0” 来指定的。
    3.抽象类是不允许被实例化的。

    #include <iostream>
    #include <Windows.h>
    
    using namespace std;
    
    class Person {
    public:
    	virtual void fun1() = 0;
    };
    class Student{
    public:
    	virtual void fun1() {
    		cout << __FUNCTION__ << endl;
    	}
    };
    int main(void) {
    	Student stu;
    	stu.fun1();
    	system("pause");
    	return 0;
    }
    
    

    展开全文
  • C#多态实现

    2022-07-28 09:28:54
    C#的多态实现,包含继承、抽象、虚函数、封装、反射等技术
  • 1、对象的上转型对象   假设Animal类是Tiger类的父类,当用子类创建一个对象,并... 4、区别   用两种方式都可以实现多态,唯一的区别就是用上转型对象可以调用父类的变量,接口回调中接口不能调用自己定义的常量。
  • c++多态及其实现

    2021-05-01 21:44:40
    c++是一门面向对象的语言,具有继承、封装和多态三大特性,本文我们总结一下c++中多态的特性及其实现方法。多态指的是调用同一接口,表现出不同的特性,分为静态多态和动态多态。静态多态指在编译期就能确定其特性的...
  • 一、多态的三种实现方式(左父右子) 第一种:父类是普通类 Fu obj = new Zi(); 第二种:父类是抽象类 Father obj = new Child(); 第三种:父类是接口 Animal obj = new Dog(); 二、多态的执行(编译看...
  • Java如何实现多态

    千次阅读 2021-02-12 10:24:44
    1、多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个...
  • 在 Java 语言中,多态主要有以下两种表现方式: 1)方法的重载(overload)。重载是指同一个类中有多个同名的方法,但这些方法有着不同的参数,因此在编译时就可以确定到底调用哪个方法,它是一种编译时多态。重载可以...
  • 多态及其实现方式

    2017-06-28 17:08:51
    定义:多态就是指不同对象收到相同消息时,会产生不同行为,同一个类在不同的场合下表现出不同的行为特征 作用:把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程...
  • 实现多态的两种方式 一、什么是多态? 父类类型的变量指向子类创建的对象,使用该变量调用父类中一个被子类重写的方法,则父类中的方法呈现出不同的行为特征,这就是多态。 简单的来说编译时方法行为表现的是...
  • java 多态实现方式

    2016-07-05 08:27:31
    条件:要有继承,重写,父类引用指向子类对象
  • 通过实例介绍了python作为动态语言,对于多态实现,以及他和静态语言关于多态的区别
  • 此文内容涉及多态的基本概念,以及java中实现多态方式,希望对大家有所帮助。 java怎么实现多态? Java中实现多态方式: 1、接口实现; 2、继承父类进行方法重写; 3、同一个类中进行方法重载。 多态存在的...
  • 多态字面意思为多种状态。在面向对象语言中,。C++中的多态性具体体现在编译和运行两个阶段。,在编译时就可以确定使用的接口。,具体引用的接口在运行时才能确定。函数重载:包括普通函数的重载和成员函数的重载...
  • 本文实例讲述了C#中多态现象和多态实现方法。分享给大家供大家参考。具体分析如下: 面向对象的特征封装、继承和多态。Polymorphism(多态性)来源于希腊单词,指“多种形态”。多态性的一个重要特征是方法的调用...
  • 4. 多态用虚函数来实现,结合动态绑定。5. 纯虚函数是虚函数再加上= 0。6. 抽象类是指包括至少一个纯虚函数的类。 纯虚函数:virtual void breathe()=0;即抽象类!必须在子类实现这个函数!即先有名称,没内容,在...
  • C++中多态的三种实现形式

    千次阅读 2021-05-23 08:34:50
    多态是一种不同的对象以单独的方式作用于相同消息的能力,这个概念是从自然语言中引进的。例如,动词“关闭”应用到不同的事务上其意思是不同的。关门,关闭银行账号或关闭一个程序的窗口都是不同的行为;其实际的...
  • C#多态的三种实现方式

    千次阅读 2021-02-16 10:18:22
    C#实现多态主要有3种方法,虚方法,抽象类,接口 1 虚方法 ​ 在父类的方法前面加关键字virtual, 子类重写该方法时在方法名前面加上override关键字,例如下面的Person类的SayHello方法 class Person { public ...
  • java中实现多态方式

    千次阅读 2021-03-06 04:02:30
    Java中实现多态方式:1、接口实现;2、继承父类进行方法重写;3、同一个类中进行方法重载。多态存在的必要条件:1、要有继承;2、要有重写;3、父类引用指向子类对象。多态的好处:1、可替换性(substitutability)...
  • 多态实现方式

    千次阅读 2013-11-23 14:25:00
    多态的形式有: 覆盖:输入参数一样,但对于不同的派生类有不同的实现, 其多态体现在运行阶段,也就是一个父类的指针可以指向不同的派生类对象,调用不同的同名函数。 重载:类的成员函数里,允许有多个不同参数的...
  • 多态的四种实现

    2020-04-11 14:29:09
    静态多态: 1.强制多态(强制类型转换) 2.过载多态(函数重载,运算符重载) 3.参数多态(类模板,函数,模板) 动态动态: 4.包含多态(虚函数) ...
  • 多态实现方式

    2021-03-08 09:20:49
    在面向对象语言中,接口的多种不同实现方式即为多态。用一句比较通俗的话说;同一操作作用于不同的对象,可以产生不同的效果。多态在生活中就像是同一个词语,用在不同的语境中,可以表达不同的意思。例子:比如有...
  • Python多态的两种实现形式

    万次阅读 2020-10-27 18:25:50
    以下是Python伪代码实现Java或C的多态: class A(object): def test(self): print('A test') class B(A): def test(self): print('B test') class C(A): def test(self): print('C t
  • Java 的接口public interface 类名接口是Java方法的合集,用于给不同的类实现同名的方法,接口是一个只有抽象方法的抽象类,1、接口中可以定义变量,但是变量必须有固定的修饰符修饰,public static final所以接口中...
  • C++ 多态 以及实现多态的三种方式

    千次阅读 2014-09-02 21:59:06
    3. C++中实现多态方式... 1 4. 细说用函数重载实现多态... 2 5. 细说用模板函数实现多态... 3 6. 小结... 4 7. 细说用虚函数实现多态... 4 7.1. 虚函数是怎么回事...
  • 3.多态实现原理 4.如何证明vptr指针? 三.总结 一.背景介绍 虚函数重写:子类重新定义父类中有相同函数名,返回值和参数的虚函数 非虚函数重写:子类重新定义父类中有相同名称和参数的非虚函数 继承中的类型...
  • Java多态实现原理

    多人点赞 2021-06-03 16:06:38
    Java多态实现原理的大致过程:首先是Java编译器将Java源代码编译成class文件。在编译过程中,会根据静态类型将调用的符号引用写到class文件中。在执行时,JVM根据class文件找到调用方法的符号引用,然后在静态类型的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 188,904
精华内容 75,561
关键字:

多态的实现方式

友情链接: 14.can瀹為獙.rar