精华内容
下载资源
问答
  • 多态表示不同的对象可以执行相同的动作,但要通过它们自己的实现代码来执行。 例:猪、狗、猫都属于动物类,我们将动物类作为父类,猪“哼哼叫”,狗“汪汪叫”,猫“喵喵叫”,猪、狗、猫三...

      在学习《大话设计模式》的时候经常会遇到多态,但什么是多态?为什么要使用多态?什么时候用多态?多态是如何实现的?使用多态有什么好处?我们将根据以上五个问题展开激烈的讨论。

    什么是多态?

      多态,顾名思义指“多种形态”。多态表示不同的对象可以执行相同的动作,但要通过它们自己的实现代码来执行。

    例:猪、狗、猫都属于动物类,我们将动物类作为父类,猪“哼哼叫”,狗“汪汪叫”,猫“喵喵叫”,猪、狗、猫三者都能叫,但三者都要通过重写父类的方法才能实现。

    为什么要使用多态?使用多态有什么好处?

      我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。

    代码重用,也称代码复用, 就是说你把一个功能写成一个模块, 以便再次需要相同功能的时候,可以直接使用,而不用重新开发。
    举例: 假如你的网站需要验证码, 你就可以把验证码这个功能单独提取出来以便复用。
    通常代码复用是通过类与对象来实现的, 这也是面向对象编程与面向过程编程最主要的区别之一。

      作为面向对象的三大特性之一,多态也有代码重用的功能,还有解决项目中紧耦合的问题,提高程序的可扩展性·。

    举例:添加一个子类,继承父类,重写父类的方法。至此,该程序的扩展性得到了提升,而又不需要查看源代码是如何实现的就可以扩展新功能。

    什么时候用多态?

    • 方法中的参数
        class Program
        {
            static void Main(string[] args)
            {
                Person p=new Person();
                Audi audi=new Audi();
                p.setDriver(audi);
                p.drive();
                SBenz benz=new SBenz();
                p.setDriver(benz);
                p.drive();
            }
        }
    
        public abstract class Driver
        {
            public abstract void run();
        }
    
        class SBenz : Driver
        {
            public override void run()
            {
                Console.WriteLine("大奔");
            }
        }
    
        class Audi:Driver
        {
            public override void run()
            {
                Console.WriteLine("奥迪");
            }
        }
    
        class Person
        {
            private Driver driver;
            public Person() { }
    
            public Person(Driver driver)
            {
                this.driver = driver;
            }
    
            public void drive()
            {
                driver.run();
            }
    
            public void setDriver(Driver driver)
            {
                this.driver = driver;
            }
        }
    
    • 方法的返回类型
        public class CarFactory
        {
            public static Driver createCar(string carName)
            {
                
                if (carName.Equals("Audi"))
                {
                    return new Audi();
                }
                else if (carName.Equals("Benz"))
                {
                    return new SBenz();
                }
                else
                {
                    Console.WriteLine("出门左拐");
                    return null;
                }
            }
        }
    

    多态是如何实现的?

    • 父类是抽象类,方法是抽象方法(没有方法体,也不能实例化),子类重写父类的方法
    • 父类中是虚方法(有方法体,能实例化),子类重写父类的方法

    小结

    • 虚方法一定要有方法体(哪怕只是大括号),抽象方法一定没有方法体
    • 虚方法可以被子类重写,抽象方法必须被子类重写
    • 如果我们不需要使用父类创建对象,它的存在只是为供子类继承。可以将父类写成抽象(关键字abstract)类,将父类的方法写成抽象方法,子类中的方法仍用关键字override重写
    • 抽象类不能被实例化
    • 多态是指类可以有多种形态,通过修改可以形成多个的实现方法。当子类从父类继承时,它会获得父类的所有方法、字段、属性和事件。若要更改父类的数据和行为,通常有两种选择,第一种是在子类的访问修饰符后加new,就是隐藏了基类(父类)的方法,第二种是在子类中重写父类的方法,更换方法里的内容。

      耐心点,坚强点,总有一天,你承受过的疼痛会有助于你,生活从来不会刻意亏欠谁,它给了你一块阴影,必会在不远的地方撒下阳光。

    展开全文
  • 接口的多种不同的实现方式即为多态。 2.多态性是允许你将父类对象设置成为一个或更多的他的子对象相等的技术。 3.我们在程序中定义的引用变量所指向的具体类型和通过改引用变量的方法调用在编程的时候并不确定,...

    官方解释:

      1.接口的多种不同的实现方式即为多态。

      2.多态性是允许你将父类对象设置成为一个或更多的他的子对象相等的技术。

      3.我们在程序中定义的引用变量所指向的具体类型和通过改引用变量的方法调用在编程的时候并不确定,相当于运行期间才确定。就是这个引用变量究竟指向那个一个实例化对象,在编译期间是不确定的,只有运行期间才确定。这样不用修改源码就可以把变量绑定到不同的实例类上,让程序拥有了多个运行状态,这就是多态。

    what!!!这是啥,不懂。解释一下

        意思就是:允许将子类类型的指针赋值给父类的指针赋值给父类类型的指针,把不同的子类对象都当作父类来看。比如你家亲戚结婚了,让你家派一个人去参加婚礼,邀请函写的是你爸的名字,但实际上是你去了,或者你的妹妹,这都可以,因为你们代表你爸,但是在你们去之前他们也不知道谁回去,只知道你们家有人去,可能是你们 的每一个成员其中的一个。这就是多态。

    多态又分为 编译时多态和运行时多态。

    编译时多态:比如重载。

    运行时多态:比如重写。

    多态的实现机制

    术语的版本:

       我们将引入java的静态分派和动态分派这个概念。

       静态分派:所有依赖静态类型来定位方法执行版本的分派动作。动态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的,而是由编译器来完成的。(编译时多态)

       动态分派:在运行期根据实际类型确定方法执行版本的分派动作。(运行时多态)

    简单版本:

    父类或者接口定义的引用变量可以指向子类或者具体实现类的实例化对象,由于程序调用方法是在运行期才动态绑定的,那么引用变量所指向的具体实例化对象运行期才确定。所以这个对象的方法是运行期正在运行的这个对象的方法而不是变量的类型中定义的方法。

     

     

     

     

     

     

     

     

    展开全文
  • 引言: 在c++中司空见惯的事情就是:可以通过指针和引用可以实现多态,而对象不可以。 那为什么?让我们来解开这神秘的暗纱! 一、类对象的存储方式: 在一个类的实例中,只会存放非静态的成员变量。 如果该类中存在...

    引言: 在c++中司空见惯的事情就是:可以通过指针和引用可以实现多态,而对象不可以。 那为什么?让我们来解开这神秘的暗纱!转载自:https://www.cnblogs.com/yinheyi/p/10525543.html

    一、类对象的存储方式:

    在一个类的实例中,只会存放非静态的成员变量。 如果该类中存在虚函数的话,再多加一个指向虚函数列表指针—vptr。

    例如声明如下两个类,并分别实例化两个对象,它们的内存分配大致如下:(vptr具体在什么位置,与编译器有关,大多数都在开始处)

    class base
    {
    public:
        virtual ~base() {};
        virtual string GetName() { return "base"; }
        GetA();
        int a;
    };
    
    class derived : public base
    {
    public:
        virtual ~derived() {};
        virtual string GetName() { return "derived";}
        GetB();
        int b;
    };
    
    base B1, B2;
    derived D1, D2;
    

    内存分布大致如下:

    1. 类对象中,只有成员变量与vptr.

    2. 普通成员函数在内存的某一位置放着。它们与c语言中定义的普通函数没有区别。 当我们通过对象或对象指针调用普通成员函数时, 编译器会拿到它。怎么拿到呢?当然是通过名字了,编译器都会对我们写的函数的名字进行修饰映射,让它们变成内存中唯一的函数名。

    3. 无论基类还是子类,每一种类类型的虚函数表只有一份,它里面存放了基类的类型信息和指向基类中的虚函数的指针。 某一类类型的所有对象都指向了相同的虚函数表。

    对象内存结构图

    二、无论通过对象还是指针,能使用的方法只与它们静态类型有关。

    例如:下面的 base类型的对象B1或指针pB1,只能使用GetName() 和GetA()方法。 无论它们是如何来的!!!!!

    // 直接构造得到
    base B1;
    base* pB1 = new base();
    
    // 即使从子类转换而来, 通过B1或pB1也永远访问不到GetB()方法。
    derived d1;
    B1 = d1;
    pB1 = new derived();
    

    三、 不同类型的指针有什么区别?

    本质上它们没有任何区别,在32/64位系统中都是4/8字节的一个变量。 唯一不同的就是编译器解释它们的方式,即通过指针来寻址出来的对象类型不同,大小不同 ,指针类型来告诉编译器如何解释该指针。

    四、 指针与引用来实现多态

    有代码如下 :

    derived* _pD = new derived();
    base* _pB = _pD;
    _pB.GetName();    // 返回 derived.
    

    想要知道如何通过指针来实现的多态,就要看看对基类指针赋值是发生了什么! 具体来说 如下图所示:

    多态赋值

    我们会发现,对指针的赋值,仅仅是让基类指针_pB指向的子类对象的地地址。 当我们使用基类指针调用GetName()函数(该函数是虚函数,它的地址在函数表中)时, 会由_pB指向的地址找到子类的虚函数表指针vptr_上海,再由vptr_上海在虚函数表中找到子类的GetName(),从而调用它。就这样实现了多态。

    五、对象不能实现多态

    有代码如下:

    base B1;
    derived D1;
    B1 = D1;
    B1.GetName();     // 返回 base
    
    base B2 = D1
    B2.GetName();    // 返回 base
    

    上面代码中无论赋值操作还是赋值构造时, 只会处理成员变量,一个类对象里面的vptr永远不会变,永远都会指向所属类型的虚函数表,操作如下图所示:

    在这里插入图片描述

    因此,通过对象调用虚函数时,就没有必要进行动态解析了,白白增加了间接性,浪费性能。编译器直接在编译时就可以确认具体调用哪一个函数了,因此没有所谓的多态。

    补充说明:

    1. 引用本质上也是通过指针的解引用(即*_point)来实现的,可以<<参考std源码剖析》一本书,所以引用也可以实现多态。

    2. 即使通过 基类的指针调用基类的虚函数 或 通过子类的指针调用子类的虚函数 以及通过子类指针调用基类的虚函数, 也是通过多态机制来完成的(即一步步的间接性来完成)。

    3. 一个空的class的对象的大小为1个字节, 编译器之所以要这么做,是为了区别同一个类类型的不同对象!

    展开全文
  • 在c++的多态中,如果一个基类的虚函数被派生类重写,那么把基类的指针指向派生类,就能够通过基类调用被派生类重写的这个虚函数。(对于这点有疑问的,可以看我之前写的C++多态,虚函数,虚函数表,gcc下的单继承,...

    在c++的多态中,如果一个基类的虚函数被派生类重写,那么把基类的指针指向派生类,就能够通过基类调用被派生类重写的这个虚函数。(对于这点有疑问的,可以看我之前写的C++多态,虚函数,虚函数表,gcc下的单继承,多继承,虚继承的内存布局)。那么如果不用指针或引用会如何?

    #include<iostream>
    using namespace std;
    class Animal{
    public:
        virtual void eat()
        {
            cout<<"能吃什么就吃什么"<<endl;
        }
        virtual void run(){}
    private:
        int name;
    };
    class Dog  : public Animal{
    public:
        virtual void eat(){
            cout<<"吃狗粮"<<endl;
        }
        virtual void shout(){}
    private:
        int age;
    };
    int main()
    {
        Dog dog;
        Animal&animal1 = dog;
        Animal* animal2 = new Dog();
        Animal animal3 = dog;
    
        animal1.eat();
        animal2->eat();
        animal3.eat();
    }
    

    执行结果:
    在这里插入图片描述
    可以看出Animal&animal1 = dog;Animal* animal2 = new Dog();都可以正常实现多态,Animal animal3 = dog 直接赋值却不可以。
    这是因为 “一个pointer或一个reference之所以支持多态,是因为它们并不引发内存任何“与类型有关的内存委托操作; 会受到改变的。只有它们所指向内存的大小和解释方式 而已”
    当一个基类对象被直接初始化为一个派生类对象是,基类对象会被切割放入较小的内存中,因此多态不再呈现

    展开全文
  • 我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了代码重用。而多态除了代码的复用性外,还可以解决项目中紧偶合的问题,提高程序的可扩展性.。耦合度讲的是...
  • 我们在实现一种程序运行时,可以选择不同的数据输入其中,当然这样最后输出的结果也是不一样的。这就是多态的思想,跟我们数学中输入不同数字到公式中产出不同结果是一个道理。下面我们就多态的定义、说明进行讲解,...
  • 什么多态?为什么要使用多态

    万次阅读 多人点赞 2018-05-22 23:02:22
    用最简单的一句话就是:父类型的引用指向子类型的对象。...首先讲下封装和继承:封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面,他把实现的细节影藏起来了,比如你在java中去实现...
  • 多态性可以通过对Bicycle类稍作修改来证明。例如,可以将printDescription方法添加类中,到显示实例中当前存储的所有数据。( For example, a printDescription method could be added to the class th
  • 实现隐藏”则通过将细节“私有化”,把接口和实现分离开来。这种类型的组织机制对那些拥有过程化程序设计背景的人来说,更容易理解,而多态的作用则是消除类型之间的耦合关系。继承允许将对象视为他自己本身的类型...
  • 2)继承抽象类的子类必须把抽象类中的所有抽象成员都重写(实现)(除非子类也是抽象类) 3)抽象类就是为了重写->多态(代码重用)、 4)抽象类中可以有实例成员也可以有抽象成员。 3.什么是抽象类(光说不做) 不...
  • 多态

    2017-04-07 08:13:30
    通过多态可以减少类中的代码量。 可以提高代码的可拓展性和可维护性。 继承是多态的基础,没有继承就没有多态。 3.实现多态的几种方式: 子类到父类的转换(向上转型)。 使用父类作为方法形参实现多态。 使用...
  • 多态什么

    2021-01-17 12:23:54
    在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象...
  • Java中的多态什么多态? 多态性是面向对象编程的三大重要特征之一,它是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中...
  • 多态实现机制

    2017-07-16 16:02:18
    多态可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制 程序实现上是这样的,通过父类指针调用子类的函数,可以让父类指针有多种形态。通过虚函数实现。 子类重新定义父类虚函数的做法...
  • 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。继承是为了重用父类代码。两个类若存在IS-A的关系就...
  • C++多态实现机制剖析

    2021-01-15 13:49:39
    继承实现了代码的复用,那么多态实现什么价值呢,简单理解就是前人写的代码(框架)可以调用后人写的代码。 1 什么多态? 多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制 ...
  • 什么多态

    2020-10-23 19:56:46
    什么多态 Java是面向对象的bai语言,多态性是面du向对象程序设计代码重用的一zhi个最强大机制,动态性的概dao念也可以被说成“一个接口,多个方法”。Java实现运行时多态性的基础是动态方法调度,它是一种在运行...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 895
精华内容 358
关键字:

多态可以通过什么实现