为您推荐:
精华内容
最热下载
问答
  • 5星
    20.37MB qq_40957277 2021-08-16 20:17:56
  • 继承是为了重用父类代码,同时为实现多态性作准备。那么什么是多态呢?方法的重写、重载与动态连接构成多态性。Java之所以引入多态的概念,原因之一是它在类的继承问题上和C++不同,后者允许多继承,这确实给其带来...

    面向对象编程有三个特征,即封装、继承和多态。

    封装隐藏了类的内部实现机制,从而可以在不影响使用者的前提下改变类的内部结构,同时保护了数据。

    继承是为了重用父类代码,同时为实现多态性作准备。那么什么是多态呢?

    方法的重写、重载与动态连接构成多态性。

    Java之所以引入多态的概念,原因之一是它在类的继承问题上和C++不同,后者允许多继承,这确实给其带来的非常强大的功能,但是复杂的继承关系也给C++开发者带来了更大的麻烦,为了规避风险,Java只允许单继承,派生类与基类间有IS-A的关系(即“猫”is a “动物”)。

    这样做虽然保证了继承关系的简单明了,但是势必在功能上有很大的限制,所以,Java引入了多态性的概念以弥补这点的不足,此外,抽象类和接口也是解决单继承规定限制的重要手段。同时,多态也是面向对象编程的精髓所在。

    要理解多态性,首先要知道什么是“向上转型”。

    我定义了一个子类Cat,它继承了Animal类,那么后者就是前者是父类。我可以通过

    Cat c = new Cat();

    实例化一个Cat的对象,这个不难理解。但当我这样定义时:

    Animal a = new Cat();

    这代表什么意思呢?

    很简单,它表示我定义了一个Animal类型的引用,指向新建的Cat类型的对象。

    由于Cat是继承自它的父类Animal,所以Animal类型的引用是可以指向Cat类型的对象的。那么这样做有什么意义呢?因为子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特,

    定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。

    所以,父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,它是无可奈何的;

    同时,父类中的一个方法只有在在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用;

    对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态连接。

    看下面这段程序:

    class Father{

    public void func1(){

    func2();

    }

    //这是父类中的func2()方法,因为下面的子类中重写了该方法

    //所以在父类类型的引用中调用时,这个方法将不再有效

    //取而代之的是将调用子类中重写的func2()方法

    public void func2(){

    System。

    out。println("AAA");

    }

    }

    class Child extends Father{

    //func1(int i)是对func1()方法的一个重载

    //由于在父类中没有定义这个方法,所以它不能被父类类型的引用调用

    //所以在下面的main方法中child。

    func1(68)是不对的

    public void func1(int i){

    System。out。println("BBB");

    }

    //func2()重写了父类Father中的func2()方法

    //如果父类类型的引用中调用了func2()方法,那么必然是子类中重写的这个方法

    public void func2(){

    System。

    out。println("CCC");

    }

    }

    public class PolymorphismTest {

    public static void main(String[] args) {

    Father child = new Child();

    child。

    func1();//打印结果将会是什么?

    }

    }

    上面的程序是个很典型的多态的例子。子类Child继承了父类Father,并重载了父类的func1()方法,重写了父类的func2()方法。重载后的func1(int i)和func1()不再是同一个方法,由于父类中没有func1(int i),那么,父类类型的引用child就不能调用func1(int i)方法。

    而子类重写了func2()方法,那么父类类型的引用child在调用该方法时将会调用子类中重写的func2()。

    那么该程序将会打印出什么样的结果呢?

    很显然,应该是“CCC”。

    对于多态,可以总结它为:

    一、使用父类类型的引用指向子类的对象;

    二、该引用只能调用父类中定义的方法和变量;

    三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)

    四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。

    多态详解(整理)2008-09-03 19:29多态是通过:

    1 接口 和 实现接口并覆盖接口中同一方法的几不同的类体现的

    2 父类 和 继承父类并覆盖父类中同一方法的几个不同子类实现的。

    一、基本概念

    多态性:发送消息给某个对象,让该对象自行决定响应何种行为。

    通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。

    java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

    1。 如果a是类A的一个引用,那么,a可以指向类A的一个实例,或者说指向类A的一个子类。

    2。 如果a是接口A的一个引用,那么,a必须指向实现了接口A的一个类的实例。

    编辑推荐:

    Spring简单实现邮件发送

    JSP标准标记库(JSTL)例程

    浅谈linksys无线路由测试。

    全部

    展开全文
    weixin_36121284 2021-02-28 18:31:40
  • 展开全部在面向对象的程序JAVA中,多态性的定义是:同一操作作用于不同的32313133353236313431303231363533e78988e69d8331333366306461类的实例,将产生不同的执行结果。对象根据所接受的消息而做出动作,同样的消息...

    展开全部

    在面向对象的程序JAVA中,多态性的定义是:

    同一操作作用于不同的32313133353236313431303231363533e78988e69d8331333366306461类的实例,将产生不同的执行结果。

    对象根据所接受的消息而做出动作,同样的消息被不同的对象接受时可能导致完全不同的行为,这种现象称为多态性。

    多态性就是多种表现形式,即用"一个对外接口,多个内在实现方法"表示。

    多态性包含编译时的多态性、运行时的多态性两大类。 即:多态性也分静态多态性和动态多态性两种。

    静态多态性

    静态多态性是指定义在一个类或一个函数中的同名函数,它们根据参数表(类型以及个数)区别语义,并通过静态联编实现。

    动态多态性

    动态多态性是指定义在一个类层次的不同类中的重载函数,它们一般具有相同的函数,因此要根据指针指向的对象所在类来区别语义,它通过动态联编实现。

    在用户不作任何干预的环境下,类的成员函数的行为能根据调用它的对象类型自动作出适应性调整,而且调整是发生在程序运行时,这就是程序的动态多态性。举例子说明一下:

    402f5f0c23c99af1822e936a7bf64c5c.png

    扩展资料:

    1.多态存在的三个必要条件:

    (1)要有继承;

    (2)要有重写;

    (3)父类引用指向子类对象。

    2.多态的好处:

    (1)可替换性(substitutability):多态对已存在代码具有可替换性,例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

    (2)可扩充性(extensibility):多态对代码具有可扩充性,增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。

    (3)接口性(interface-ability):多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。

    (4)灵活性(flexibility):它在应用中体现了灵活多样的操作,提高了使用效率。

    (5)简化性(simplicity):多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

    参考资料来源:

    展开全文
    weixin_33477210 2021-02-12 09:33:32
  • 多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphisn),字面意思多种形状。 C++多态性是通过虚函数来实现的,虚函数允许子类重新定义...

    多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。多态(polymorphisn),字面意思多种形状。

    C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为重写。(这里我觉得要补充,重写的话可以有两种,直接重写成员函数和重写虚函数,只有重写了虚函数的才能算作是体现了C++多态性)而重载则是允许有多个同名的函数,而这些函数的参数列表不同,允许参数个数不同,参数类型不同,或者两者都不同。编译器会根据这些函数的不同列表,将同名的函数的名称做修饰,从而生成一些不同名称的预处理函数,来实现同名函数调用时的重载问题。但这并没有体现多态性。

    多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。

    那么多态的作用是什么呢,封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。

    最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。

    一、定义

    纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”

    virtual void funtion()=0

    二、引入原因

    1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。

    2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。

    为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()=0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。

    三、相似概念

    1、多态性

    指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。

    a、编译时多态性:通过重载函数实现

    b、运行时多态性:通过虚函数实现。

    2、虚函数

    虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态覆盖(Override)

    3、抽象类

    包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。

    虚析构函数的特点(动态绑定)

    Base*p=new Derived();

    delete p;

    删除Base类型的指针时,会调用析构函数,如果Base类型的析构函数的虚函数,则会按照虚函数的动态绑定,先调用Derived的析构函数,然后调用Base的析构函数。

    以这样的方式会调用多次析构函数。

    C++类成员和数据成员初始化总结

    C++为类中提供类成员的初始化列表

    类对象的构造顺序是这样的:

    1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员

    2.进入构造函数后在构造函数中执行一般计算

    1.类里面的任何成员变量在定义时是不能初始化的。

    2.一般的数据成员可以在构造函数中初始化。

    3.const数据成员必须在构造函数的初始化列表中初始化。

    4.static要在类的定义外面初始化。

    5.数组成员是不能在初始化列表里初始化的。

    6.不能给数组指定明显的初始化。

    这6条一起,说明了一个问题:C++里面是不能定义常量数组的!

    C++类的初始化:

    1.初始化列表:CSomeClass::CSomeClass() : x(0), y(1){}

    2.类外初始化:int CSomeClass::myVar=3;

    3.const常量定义必须初始化,C++类里面使用初始化列表;

    4.C++类不能定义常量数组。

    免费领取C++学习资料一份

    在这里插入图片描述

    展开全文
    kaikeba 2020-12-28 18:50:10
  • 虚拟功能函数名称重载运算符重载除了上述三种类型的多态性外,还存在其他种类的多态性:运行编译时间ad-hoc多态性参数多态性我知道运行时多态性可以通过虚函数来实现静态多态性可以通过模板函数实现但对于另外两个ad...

    据我所知:

    C ++提供了三种不同类型的多态性。

    虚拟功能

    函数名称重载

    运算符重载

    除了上述三种类型的多态性外,还存在其他种类的多态性:

    运行

    编译时间

    ad-hoc多态性

    参数多态性

    我知道运行时多态性可以通过虚函数来实现

    静态多态性可以通过模板函数实现

    但对于另外两个

    ad-hoc多态性

    参数多态性

    该网站说,

    ad-hoc多态性:

    如果可以使用的实际类型的范围是有限的,并且必须在使用之前单独指定组合,则这称为ad-hoc多态。

    参数多态性:

    如果所有代码都是在没有提及任何特定类型的情况下编写的,因此可以透明地使用任意数量的新类型,这称为参数多态。

    我几乎无法理解他们:(

    任何人都可以用一个例子解释他们两个吗?

    我希望这些问题的答案对他们大学的许多新的消息有所帮助。

    实际上,C ++有四种多态:参数(通过C ++模板的通用性),包含(通过C ++中的虚方法进行子类型化),重载和强制(隐式转换)。在概念上,函数重载和运算符重载之间几乎没有区别。

    因此,我提到的网站似乎误导了许多......我是否正确?

    @zombie:该网站涉及很多好的概念,但在使用术语方面并不精确和一致(例如,一旦开始谈论虚拟调度/运行时多态性,它就会产生很多关于多态性的陈述,这些陈述一般都是错误的但对于虚拟调度来说却是如此)。如果您已经理解了这个主题,您可以了解所说的内容和精神上插入必要的警告,但通过阅读网站很难到达那里....

    有些术语是近似同义词,或者比其他术语更相关但更受限制。例如,根据我的经验,术语"ad-hoc多态"主要用于Haskell,但"虚函数"非常密切相关。细微差别在于"虚函数"是一个面向对象的术语,指的是具有"后期绑定"的成员函数。"多次发送"也是一种特殊的多态性。正如FredOverflow所说,运算符和函数重载基本上都是一样的。

    我为你修改了你的格式。请阅读编辑窗格右侧的可用帮助。有> 200个问题且> 3k的人应该知道这个基本的东西。此外,您可能想购买新的键盘。这个转移关键似乎是间歇性的失败。哦,并且:在C ++中没有"模板函数"这样的东西。但是,有功能模板。

    @ sbi,人们在采访中面对这个问题,"模板功能和功能模板之间有什么区别"?如果没有这样的话,他们为什么要问? comeaucomputing.com/techtalk/templates/#terms

    @zombie:在那篇文章中,Greg解释说,通常称为"模板功能"的是"功能模板"。他说功能模板实例可以称为"模板功能"。你是否以这种方式使用这个词?我建议不要使用它。这是误导,因为它被错误地使用了。

    好的我同意我刚才提到的网站,因为你的评论"没有"模板功能"

    @zombie:我不知道Greg使用过它,这是我第一次听到它的使用方式,这就是为什么我认为不会有这样的野兽。

    @sbi - 只是澄清 - 你是说"功能模板"是未实例化的模板,而"模板功能"是(最好避免使用的术语)实例化的功能?混乱似乎对我来说是可以理解的。通过英语语法,通常有一个"xy" - >"y的x"替换模式用于名词一起使用,所以"函数模板" - >"函数模板"是有意义的,但"模板函数" - >"模板的功能"似乎并没有真正暗示"实例化"给我。如果有的话,它使用"函数"的不同含义来暗示"模板的目的"。

    @Steve:一个功能模板是一个模板,您可以从中生成功能(就像桌布是一块布在桌子上的布料,婴儿油是由婴儿制成的油:))。现在,Greg说,模板函数是一个从模板生成的函数。我说这是一个相当不错的术语,除了使用术语模板功能的其他人正在错误地使用它来引用功能模板。

    @sbi - 从你的双关语中删除双关语,婴儿油是为婴儿制造的油。我从学校记得的x模式的x y - > y大概是一个模糊的概括,其中"of"通常应该用更具体的东西代替。你对歧义的主张对我来说似乎很强烈,但在双关语之外,我们不会说"婴儿油"含糊不清 - 有一个普遍接受的含义,所以多词这个术语本身就是一个单词。"模板功能"是否有普遍接受的含义?错误地使用"模板功能"的常见程度如何?

    @Steve:我知道为什么它被称为婴儿油,这只是一个笑话,并没有使我所说的无效。"类模板"不含糊不清("类的模板"似乎是正确的),它是正确的术语。正如我写的那样,Gregs术语是我第一次遇到"模板类",它没有(错误地)引用类模板,我经常听到它称为"模板类"。

    @sbi - 对不起,如果遇到错误的话。如果我只是评论"常见的"模板功能"错误使用?"它不清楚我得到了什么。我知道你在开玩笑,而且大多数情况下我并不打算让你说的话无效 - 我只是在提出我的问题和建议。关于但人类语言是由共同使用方面定义的,这只是我的一个痴迷的口号 - 一个反复出现的笑话(尽管有一点背后),你不应该亲自接受。

    @Steve:现在我读了它,我发现我的回复可能比当时的意思更加严厉。我道歉。无论如何,它经常被错误地使用,所以经常使用错误而不是经常使用错误。但我仍然认为这是错误的。首先是出于迂腐的原因(每个C ++都是一个学者),但也出于教学原因:术语"模板类",当应用于类模板时,错误地暗示事物是一个类,而不是,通常会让新手混淆他们试图使用需要类的模板。

    @sbi:仅仅是为了讨论 - 并且值得所有2c恕我直言 - 另一个可能的原因,有些人可能会因为"模板"而导致领先,在源代码中按顺序遇到关键字:(模板...函数)和(模板......类)。

    了解/多态性的要求

    要理解多态性 - 正如计算科学中使用的术语 - 从简单的测试和定义开始是有帮助的。考虑:

    Type1 x;

    Type2 y;

    f(x);

    f(y);

    这里,f()是执行某些操作,并且给出值x和y作为输入。

    To exhibit polymorphism, f() must be able to operate with values of at least two distinct types (e.g. int and double), finding and executing distinct type-appropriate code.

    Ok.

    多态的C ++机制

    显式程序员指定的多态性

    您可以编写f(),以便它可以通过以下任何方式在多种类型上运行:

    预处理:

    #define f(X) ((X) += 2)

    // (note: in real code, use a longer uppercase name for a macro!)

    重载:

    void f(int& x)    { x += 2; }

    void f(double& x) { x += 2; }

    模板:

    template

    void f(T& x) { x += 2; }

    虚拟发货:

    struct Base { virtual Base& operator+=(int) = 0; };

    struct X : Base

    {

    X(int n) : n_(n) { }

    X& operator+=(int n) { n_ += n; return *this; }

    int n_;

    };

    struct Y : Base

    {

    Y(double n) : n_(n) { }

    Y& operator+=(int n) { n_ += n; return *this; }

    double n_;

    };

    void f(Base& x) { x += 2; } // run-time polymorphic dispatch

    其他相关机制

    编译器提供的内置类型,标准转换和转换/强制的多态性将在后面讨论完整性,如下所示:

    无论如何,它们通常被直观地理解(保证"哦,那个"反应),

    它们影响了要求的门槛,以及使用上述机制的无缝性,以及

    解释是对更重要概念的一种分散注意力。

    术语

    进一步分类

    鉴于上述多态机制,我们可以通过各种方式对它们进行分类:

    何时选择了多态类型特定代码?

    运行时意味着编译器必须为程序在运行时可能处理的所有类型生成代码,并且在运行时选择正确的代码(虚拟调度)

    编译时间意味着在编译期间选择特定于类型的代码。这样做的结果是:假设一个程序仅使用int参数调用上面的f - 取决于所使用的多态机制和内联选择,编译器可能会避免为f(double)生成任何代码,或者生成的代码可能会丢弃一些指向编译或链接。 (除虚拟调度外的所有上述机制)

    支持哪些类型?

    Ad-hoc意味着您提供显式代码来支持每种类型(例如重载,模板专门化);你明确地添加支持"为此"(根据ad hoc的意思)类型,其他一些"这个",也许"那个"也是;-)。

    参数含义您可以尝试将该函数用于各种参数类型,而无需专门执行任何操作来启用它对它们的支持(例如模板,宏)。具有与模板/宏期望1相同的函数/运算符的对象是模板/宏需要完成其工作的所有对象,其确切类型无关紧要。从C ++ 11中删除的"概念"有助于表达和实施这些期望 - 让我们希望它们成为后来的标准。

    参数多态提供了鸭子打字 - 这个概念归功于James Whitcomb Riley,他明显地说:"当我看到一只像鸭子一样行走的小鸟,像鸭子一样游泳,像鸭子一样呱呱叫,我称这只鸟为鸭子。"

    template

    void do_ducky_stuff(const Duck& x) { x.walk().swim().quack(); }

    do_ducky_stuff(Vilified_Cygnet());

    子类型(又名包含)多态性允许您在不更新算法/函数的情况下处理新类型,但它们必须从相同的基类派生(虚拟调度)

    1 - 模板非常灵活。 SFINAE(另见std::enable_if)有效地允许参数多态的几组期望。例如,您可能编码,当您正在处理的数据类型具有.size()成员时,您将使用一个函数,否则另一个函数不需要.size()(但可能会以某种方式受到影响 - 例如使用较慢的strlen()或不在日志中打印有用的消息)。您还可以在使用特定参数实例化模板时指定临时行为,或者保留一些参数参数(部分模板特化)或不参与(完全特化)。

    "多态"

    Alf Steinbach评论说,在C ++标准中,多态只引用了使用虚拟调度的运行时多态。一般比较科学。根据C ++创建者Bjarne Stroustrup的词汇表(http://www.stroustrup.com/glossary.html),意思更具包容性:

    polymorphism - providing a single interface to entities of different types. Virtual functions provide dynamic (run-time) polymorphism through an interface provided by a base class. Overloaded functions and templates provide static (compile-time) polymorphism. TC++PL 12.2.6, 13.6.1, D&E 2.9.

    Ok.

    这个答案 - 就像问题一样 - 将C ++特性与Comp相关联。科学。术语。

    讨论

    使用C ++标准使用比"Comporp"更窄的"多态"定义。科学。社区,以确保您的受众的相互理解考虑...

    使用明确的术语("我们可以使这些代码可以重用于其他类型吗?"或"我们可以使用虚拟调度吗?"而不是"我们可以使这段代码具有多态性吗?")和/或

    明确定义您的术语。

    但是,成为一名优秀的C ++程序员至关重要的是理解多态性真正为你做的事情......

    让你编写一次"算法"代码,然后将其应用于许多类型的数据

    ...然后非常清楚不同的多态机制如何与您的实际需求相匹配。

    运行时多态性适合:

    输入由工厂方法处理并作为通过Base* s处理的异构对象集合吐出,

    基于配置文件,命令行开关,UI设置等在运行时选择的实现,

    实现在运行时变化,例如状态机模式。

    当没有明确的运行时多态性驱动程序时,编译时选项通常更可取。考虑:

    模板化类的compile-what-c??alled方面比运行时失败的fat接口更可取

    SFINAE

    CRTP

    优化(许多包括内联和死代码消除,循环展开,基于静态堆栈的数组vs堆)

    __FILE__,__LINE__,字符串文字串联和宏的其他独特功能(仍然是邪恶的;-))

    支持模板和宏测试语义使用,但不要人为地限制提供支持的方式(因为虚拟调度往往需要完全匹配的成员函数覆盖)

    支持多态性的其他机制

    正如所承诺的,为了完整性,涵盖了几个外围主题:

    编译器提供的重载

    转换

    铸就/胁迫

    这个答案最后讨论了上述如何结合使用和简化多态代码 - 特别是参数多态(模板和宏)。

    映射到特定于类型的操作的机制

    >隐式编译器提供的重载

    从概念上讲,编译器会为内置类型重载许多运算符。它在概念上与用户指定的重载不同,但是因为它很容易被忽略而被列出。例如,您可以使用相同的符号x += 2添加到int和double,并且编译器会生成:

    特定于类型的CPU指令

    相同类型的结果。

    然后重载无缝扩展到用户定义的类型:

    std::string x;

    int y = 0;

    x += 'c';

    y += 'c';

    编译器提供的基本类型的重载在高级(3GL +)计算机语言中很常见,并且对多态性的明确讨论通常意味着更多。 (2GL - 汇编语言 - 通常要求程序员明确地为不同类型使用不同的助记符。)

    >标准转换

    C ++标准的第四部分描述了标准转换。

    第一点很好地总结了(从一个旧的草案 - 希望仍然基本上正确):

    -1- Standard conversions are implicit conversions defined for built-in types. Clause conv enumerates the full set of such conversions. A standard conversion sequence is a sequence of standard conversions in the following order:

    Ok.

    来自以下集合的零或一次转换:左值到右值的转换,数组到指针的转换以及函数到指针的转换。

    来自以下集合的零或一次转换:整数促销,浮点促销,积分转换,浮点转换,浮点积分转换,指针转换,成员转换指针和布尔转换。

    零或一个资格转换。

    [Note: a standard conversion sequence can be empty, i.e., it can consist of no conversions. ] A standard conversion sequence will be applied to an expression if necessary to convert it to a required destination type.

    Ok.

    这些转换允许以下代码:

    double a(double x) { return x + 2; }

    a(3.14);

    a(42);

    应用早期测试:

    To be polymorphic, [a()] must be able to operate with values of at least two distinct types (e.g. int and double), finding and executing type-appropriate code.

    Ok.

    a()本身专门为double运行代码,因此不是多态的。

    但是,在第二次调用a()时,编译器知道为"浮点提升"(标准§4)生成适合类型的代码,以将42转换为42.0。额外的代码在调用函数中。我们将在结论中讨论这一点的重要性。

    >胁迫,演员,隐含的构造者

    这些机制允许用户定义的类指定类似于内置类型的标准转换的行为。我们来看一下:

    int a, b;

    if (std::cin >> a >> b)

    f(a, b);

    这里,在转换运算符的帮助下,在布尔上下文中计算对象std::cin。这可以在概念上与来自上述主题中的标准转换的"整体促销"等组合。

    隐式构造函数有效地做同样的事情,但是由强制转换类型控制:

    f(const std::string& x);

    f("hello");  // invokes `std::string::string(const char*)`

    编译器提供的重载,转换和强制的含义

    考虑:

    void f()

    {

    typedef int Amount;

    Amount x = 13;

    x /= 2;

    std::cout << x * 1.1;

    }

    如果我们希望在分割期间将x金额视为实数(即为6.5而不是向下舍入为6),我们只需要更改为typedef double Amount。

    这很好,但是使代码明确地"输入正确"并不是太多的工作:

    void f()                               void f()

    {                                      {

    typedef int Amount;                    typedef double Amount;

    Amount x = 13;                         Amount x = 13.0;

    x /= 2;                                x /= 2.0;

    std::cout << double(x) * 1.1;          std::cout << x * 1.1;

    }                                      }

    但是,请考虑我们可以将第一个版本转换为template:

    template

    void f()

    {

    Amount x = 13;

    x /= 2;

    std::cout << x * 1.1;

    }

    这是由于那些小的"便利功能",它可以很容易地为int或double实例化并按预期工作。没有这些功能,我们需要显式的强制转换,类型特征和/或策略类,一些冗长,容易出错的混乱,如:

    template

    void f()

    {

    Amount x = Policy::thirteen;

    x /= static_cast(2);

    std::cout << traits::to_double(x) * 1.1;

    }

    因此,编译器提供的运算符重载内置类型,标准转换,转换/强制/隐式构造函数 - 它们都为多态性提供了微妙的支持。从这个答案顶部的定义,他们通过映射来解决"查找和执行类型适当的代码":

    从参数类型"离开"

    来自众多数据类型的多态算法代码处理

    为(可能较少)(相同或其他)类型编写的代码。

    从常量类型的值"到"参数类型

    它们本身并不建立多态上下文,但确实有助于在这种上下文中赋予/简化代码。

    你可能会觉得被骗了......看起来并不多。重要的是,在参数化多态上下文(即内部模板或宏)中,我们试图支持任意大范围的类型,但通常希望根据为其设计的其他函数,文字和操作来表达对它们的操作。一小组类型。当操作/值在逻辑上相同时,它减少了在每种类型的基础上创建几乎相同的功能或数据的需要。这些功能相互配合,增加了"尽力而为"的态度,通过使用有限的可用功能和数据来做直觉预期的事情,并且只有在存在真正的模糊性时才会停止错误。

    这有助于限制对支持多态代码的多态代码的需求,围绕多态性的使用绘制更紧密的网络,因此本地化使用不会强制广泛使用,并且可以根据需要提供多态性的好处,而不必承担必须暴露实现的成本编译时,在目标代码中具有相同逻辑功能的多个副本以支持使用的类型,并且在进行虚拟分派时与内联或至少编译时解析的调用相反。正如C ++中的典型情况一样,程序员可以自由地控制使用多态的边界。

    好。

    -1除术语讨论外,答案很棒。 C ++标准在1.8 / 1中定义术语"多态",参考关于虚函数的第10.3节。所以没有摆动的空间,没有讨论的余地,没有个人观点的余地:在标准C ++的背景下,这个术语是一劳永逸地定义的。它确实发挥了实践作用。例如,5.2.7 / 6 about dynamic_cast需要"指向多态类型的指针或左值"。干杯&hth。,

    @Alf:很好的参考 - 尽管我认为你的观点太狭隘了。从列出重载,ad-hoc和参数多态等的问题中可以清楚地看出答案应该将C ++的功能与通用Comp相关联。科学。术语的含义。实际上,Stroustrups词汇表说"多态 - 为不同类型的实体提供单一接口。虚函数通过基类提供的接口提供动态(运行时)多态性。重载函数和模板提供静态(编译时)多态性。 TC ++ PL 12.2.6,13.6.1,D&E 2.9。"

    www2.research.att.com/~bs/glossary.html

    @Tony:这不是你答案的主旨是错误的。没问题,很棒。它只是那个。你得到它的术语:正式的学术术语是由神圣国际标准定义的狭义术语,而人们可能意味着稍微不同的东西的非正式粗略术语是主要用于这个问题和答案的术语。干杯&hth。,

    @Alf:我希望答案很好 -"其他机制"需要在五分之一的行中重写,我正在考虑/起草一个更具体的特征 - 与多态机制形成对比的含义。无论如何,我的理解是,正式的学术专用 - 以C ++为重点的意义可能是狭隘的,但正式的学术一般的Comp。科学。意思不是,正如Stroustrups词汇表所证明的那样。我们需要一些明确的东西 - 例如Knuth的定义 - 没有运气,谷歌搜索。我很感谢你是一位C ++大师,但是你能指出相关的相关证据吗?

    @Alf:不是它的确定性,而只是通过显示我并非完全孤独;-) en.wikipedia.org/wiki/Polymorphism_(computer_science)

    @Tony:我已经指出:标准正式定义了1.8 / 1中的"多态"(当一个术语被内联定义时,它的设置用斜体表示)。对于计算机编程语言,您无法获得比其国际标准更具权威性或更高权威性。例如,如果Bjarne说出与标准(和他有)相矛盾的东西,那么它就是规则的标准,而Bjarne必须鞠躬 - 就像我们所有人一样。但总的来说,使用更一般的基于概念的术语。由于没有正式定义,它是非正式的。不要把学术与正式混为一谈。是吗?

    @Alf:这里的第一个问题是问题的主要背景:一个人手持一些Comp。科学。询问C ++特性如何与这些术语相关的术语。他们不是在C ++标准的背景下询问这些术语的含义。这些术语在科学意义上不是绝对的,它们是符号的便利 - 请参阅stackoverflow.com/questions/5387412/作为示例。因此,如果这些含义不同,则值得注意但不是更多。

    @Alf:其次,我相信多态性在任何体面的通用Comp中都是正式定义的。科学。以与我的使用(和Stroustrups)兼容的(永恒,稳定)方式预订。维基百科的文章链接了一些以这种方式定义它的学术出版物:"多态函数是其操作数(实际参数)可以有多种类型的函数。多态类型是其操作适用于多种类型的值的类型。" (来自lucacardelli.name/Papers/OnUnderstanding.A4.pdf)。所以,问题是"谁为Comp.Sci说话"......?

    @Alf:我不认为Comp内部有任何重大争议。科学。对于那个问题,虽然肯定在较窄的上下文中,如讨论仅提供运行时多态性,C ++标准或OO编程的语言,但采用的是较窄的视图。我从来没有听说过维基百科所链接的大多数学者,所以看到像Knuth这样的人的正式定义会很好。但是,C ++标准基本上是一个工程合同......它以一种传达要求的方式使用术语,而不是用于科学准确性。它不是这样的权威。

    Duck-typing是(隐式)约束多态 - 该函数仅适用于支持quacking的类型。 C ++中的SFINAE规则意味着模板以这种方式被隐式约束。"参数"和"不受约束"通常用作同义词WRT多态性。严格地说,即使在像Haskell这样的语言中,受约束的参数多态性也与ad-hoc多态性(ad-hoc在类实例中)是分开的,但趋势是将"无约束"和"参数"视为同义词,因为附带条件不同,在C ++中应用这些术语会让人感到困惑。

    @ Steve314:抱歉,我正在努力追随。你是说鸭子打字与参数多态不同,因为它需要支持约束(如承诺的C ++ 0xs Concepts)或基于类型属性的重载分辨率ala SFINAE?在模板实例化或宏扩展获得致命的编译器错误之前,某些测试"支持quacking的类型"的关键区别是指导实现的选择或定制吗?我的google-foos没有出现鸭子打字这方面的先例 - 你知道关于这个的任何定义/文章吗?

    @Tony D - 它只是一个观察 - 在阅读这个答案之前,我从未考虑相对于参数/特殊分类的鸭子打字。在Haskell中工作,如果需要约束类型(例如,支持

    @Tony D -"ad-hoc"和"约束"倾向于被认为是Haskell中的同义词的原因是因为它们是通过相同语言特征的(不同方面)实现的 - 类型类。如果没有该功能,您所拥有的只是无约束的参数多态,因此它们也被视为同义词。严格地说,在Haskell中,参数多态通过指定类型类约束来约束,并且类型类的方法(单独)是临时的,因为每个类型都使用自己的实现定义自己的实例。

    @Tony D - 如果那个精确的形式意义是人们真正意味着什么不是问题,但他们通常不会。无论如何,由于"约束多态"和"ad-hoc多态"经常被视为同义词,我认为重要的是要注意模板中的参数多态(和鸭子类型)是隐式约束的 - 你没有声明你的类型必须支持quacking但是,如果它不能嘎嘎叫它就像鸳鸯一样嘎嘎叫。在Haskell中,约束是显式的。在C ++中,通过SFINAE,它是一个隐式静态约束。在Python中它是一个运行时错误,但仍然是一个约束。

    @Tony D - 另外在C ++中,您有模板专业化 - 您可以提供模板的临时替代实现,在特定情况下覆盖它。这是SFINAE"不是错误"方面的一个原因 - 另一个模板可能提供正确的替代方案。这是ad-hoc多态,因为有多个实现 - 多个模板。它受约束,因为每个模板都有约束 - 一些隐式(只有带有这些操作的类型,只有更专业的模板不存在的情况)和一些显式。

    @Tony D - 我应该删除所有这些评论(和我的答案)并写一篇博文。

    @ Steve314:"C ++在编译时通过SFINAE错误进行can-it-quack检查 - 模板不会实例化" - 不使用SFINAE的模板会在x.quack()产生编译时错误,而SFINAE允许编译时测试并通过另一个功能来避免错误,甚至不试图嘎嘎叫。如果需要更明确的致命检查,那么我们有库提供的概念,例如boost.org/doc/libs/1_54_0/libs/concept_check/concept_check.htm。但这些只是围绕参数多态性报告的编译时错误的方式/位置进行了转换。

    @ Steve314:哦 - 没有意识到你已经发布了一个答案 - 我有一个阅读(如果它还在那里!);-)

    @Tony D - 抱歉 -"通过SFINAE错误"是一个脑力计,我的意思是"通过SFINAE规则"。我不确定是否有不同意见 - 澄清我在说什么,当你在模板中调用T::quack ()时,隐含地将该模板限制为只为具有quack ()的T类型实例化。即使你为没有它的某个类型T实例化,quack也不是错误,但是如果没有其他模板覆盖那个案例,那就是错误。所以它不是一个在某些情况下有错误的通用模板,它是一个带有隐式约束的模板。

    @ Steve314我怀疑是在谈论相同的知识,只是无法毫不含糊地沟通,知道同意;-)。整蛊! SFINAE在至少一个潜在匹配中往往非常明确:您必须在函数参数或返回类型中进行测试(即使您真的只想在函数体中使用属性),并且在实践中它通常使用std::enable_if或类似于方便和强调SFINAE功能匹配标准的性质。然而,并非所有候选人都会明确地与SFINAE相关的代码混乱。

    @TonyD:非常好的答案,但我的问题是如何以及为什么strlen()函数更慢?

    @PravasiMeet:每个std::string对象跟踪自己的.size(),因此您可以随时读取成员变量,但strlen(const char*)必须扫描并计算文本中的每个字符,直到找到ASCII NUL终结符 - 文本越长,strlen()越长。大多数编译器会在编译时评估strlen()的字符串文字(例如strlen("abc")) - 所以至少在有限的情况下它是无关紧要的......)

    在C ++中,重要的区别是运行时绑定和编译时绑定。 Ad-hoc与参数并没有多大帮助,我稍后会解释。

    |----------------------+--------------|

    | Form                 | Resolved at  |

    |----------------------+--------------|

    | function overloading | compile-time |

    | operator overloading | compile-time |

    | templates            | compile-time |

    | virtual methods      | run-time     |

    |----------------------+--------------|

    注意 - 运行时多态性仍然可以在编译时解析,但这只是优化。需要有效地支持运行时解析,并与其他问题进行权衡,这是导致虚拟功能成为现实的一部分。这对于C ++中所有形式的多态性来说都是非常关键的 - 每一种都来自不同背景下的不同权衡取舍。

    函数重载和运算符重载在各方面都是相同的。使用它们的名称和语法不会影响多态性。

    模板允许您一次指定许多函数重载。

    还有另一组名称用于同一分辨时间的想法......

    |---------------+--------------|

    | early binding | compile-time |

    | late binding  | run-time     |

    |---------------+--------------|

    这些名称与OOP更相关,因此说模板或其他非成员函数使用早期绑定有点奇怪。

    为了更好地理解虚函数和函数重载之间的关系,理解"单调度"和"多调度"之间的区别也很有用。这个想法可以被理解为一个进步......

    首先,有单形函数。函数的实现由函数名唯一标识。没有参数是特殊的。

    然后,有单一的派遣。其中一个参数被认为是特殊的,并使用(以及名称)来标识要使用的实现。在OOP中,我们倾向于将此参数视为"对象",在函数名称之前列出它等。

    然后,有多个派遣。任何/所有参数都有助于确定要使用的实现。因此,再一次,没有一个参数需要特殊。

    OOP显然比提名一个特殊参数的借口更多,但这只是其中的一部分。回顾我所说的权衡 - 单一调度很容易有效(通常的实现称为"虚拟表")。多次调度更加尴尬,不仅在效率方面,而且在单独编译方面。如果你很好奇,你可能会查找"表达问题"。

    正如对非成员函数使用术语"早期绑定"有点奇怪,使用术语"单一调度"和"多次调度"有点奇怪,其中多态性在编译时被解析。通常,C ++被认为不具有多个分派,这被认为是一种特定的运行时分辨率。但是,函数重载可以看作是在编译时完成的多次调度。

    回到参数化和ad-hoc多态性,这些术语在函数式编程中更受欢迎,并且它们在C ++中不太起作用。尽管如此...

    参数多态意味着您将类型作为参数,并且无论您使用哪种类型的参数,都会使用完全相同的代码。

    Ad-hoc多态性是ad-hoc,因为您根据特定类型提供不同的代码。

    重载和虚函数都是ad-hoc多态的例子。

    再次,有一些同义词......

    |------------+---------------|

    | parametric | unconstrained |

    | ad-hoc     | constrained   |

    |------------+---------------|

    除了这些不是完全同义词,尽管它们通常被视为它们,并且这可能是C ++中可能产生混淆的地方。

    将这些视为同义词的原因在于,通过将多态性约束到特定类型的类,可以使用特定于这些类类型的操作。这里的"类"一词可以在OOP意义上解释,但实际上只是指(共同命名)共享某些操作的类型集。

    因此,通常采用参数多态(至少在默认情况下)来暗示不受约束的多态性。因为无论类型参数如何都使用相同的代码,所以唯一可支持的操作是适用于所有类型的操作。通过保留不受约束的类型集,您严格限制可应用于这些类型的操作集。

    在例如哈斯克尔,你可以......

    myfunc1 :: Bool -> a -> a -> a

    myfunc1 c x y = if c then x else y

    这里的a是一种无约束的多态类型。它可以是任何东西,所以我们对这种类型的值的处理力度不大。

    myfunc2 :: Num a => a -> a

    myfunc2 x = x + 3

    这里,a被约束为Num类的成员 - 类似于数字的类型。该约束允许您使用这些值执行数字操作,例如添加它们。即使3是多态的 - 类型推断也表明你的意思是a类型的3。

    我认为这是受约束的参数多态。只有一个实现,但它只能在受限情况下应用。 ad-hoc方面是选择使用哪个+和3。 Num的每个"实例"都有自己独特的实现。因此即使在Haskell中,"参数化"和"不受约束"也不是真正的同义词 - 不要怪我,这不是我的错!

    在C ++中,重载和虚函数都是ad-hoc多态。 ad-hoc多态的定义并不关心是在运行时还是在编译时选择实现。

    如果每个模板参数都具有类型typename,则C ++与模板的参数多态非常接近。有类型参数,无论使用哪种类型,都有一个实现。但是,"替换失败不是错误"规则意味着由于在模板中使用操作而产生隐式约束。其他复杂性包括用于提供替代模板的模板专业化 - 不同(ad-hoc)实现。

    因此,在某种程度上,C ++具有参数多态性,但它是隐式约束的,并且可以被ad-hoc备选方案覆盖 - 即这种分类对C ++并不真正起作用。

    好。

    +1很多有趣的观点和见解。我只花了几个小时阅读Haskell,所以"a这里是一个不受约束的多态类型[...]因此我们对这种类型的值所做的事情并不多。"感兴趣 - 在C ++中没有概念你不仅限于在指定为模板参数的类型的参数上尝试一组特定的操作...像boost概念这样的库以另一种方式工作 - 确保类型支持你指定的操作而不是防止意外使用额外的操作。

    @Tony - 概念是一种明确约束模板多态性的方法。由于兼容性,隐式约束显然不会消失,但显式约束肯定会显着改善事物。我很确定一些过去的概念计划与Haskell类型类有些相关,虽然我没有深入研究它们,当我最后看起来"浅薄"时我并不知道Haskell。

    "由于兼容性,隐式约束显然不会消失" - 来自内存,C ++ 0x Concepts确实(承诺: - /)防止"隐式约束" - 你只能以概念承诺的方式使用类型。

    这可能没有任何帮助,但我通过为主函数提供定义的函数(如START和END)来向我的朋友介绍编程,因此它并不太令人生畏(它们只使用了main。 cpp文件)。它包含多态类和结构,模板,向量,数组,前处理程序指令,友谊,运算符和指针(在尝试多态之前你应该知道所有这些):

    注意:它还没有完成,但你可以得到这个想法

    main.cpp中

    #include"main.h"

    #define ON_ERROR_CLEAR_SCREEN false

    START

    Library MyLibrary;

    Book MyBook("My Book","Me");

    MyBook.Summarize();

    MyBook +="Hello World";

    MyBook +="HI";

    MyBook.EditAuthor("Joe");

    MyBook.EditName("Hello Book");

    MyBook.Summarize();

    FixedBookCollection FBooks("Fairytale Books");

    FairyTale MyTale("Tale","Joe");

    FBooks += MyTale;

    BookCollection E("E");

    MyLibrary += E;

    MyLibrary += FBooks;

    MyLibrary.Summarize();

    MyLibrary -= FBooks;

    MyLibrary.Summarize();

    FixedSizeBookCollection<5> Collection("My Fixed Size Collection");

    /* Extension Work */ Book* Duplicate = MyLibrary.DuplicateBook(&MyBook);

    /* Extension Work */ Duplicate->Summarize();

    END

    main.h

    #include

    #include

    #include

    #include

    #include

    #include

    #ifndef __cplusplus

    #error Not C++

    #endif

    #define START int main(void)try{

    #define END GET_ENTER_EXIT return(0);}catch(const std::exception& e){if(ON_ERROR_CLEAR_SCREEN){system("cls");}std::cerr <

    #define GET_ENTER_EXIT std::cout <

    class Book;

    class Library;

    typedef std::vector Books;

    bool sContains(const std::string s, const char c){

    return (s.find(c) != std::string::npos);

    }

    bool approve(std::string s){

    return (!sContains(s, '#') && !sContains(s, '%') && !sContains(s, '~'));

    }

    template bool isBook(){

    return (typeid(C) == typeid(Book) || std::is_base_of());

    }

    template class DuplicatableClass{

    public:

    ClassToDuplicate* Duplicate(ClassToDuplicate ToDuplicate){

    return new ClassToDuplicate(ToDuplicate);

    }

    };

    class Book : private DuplicatableClass{

    friend class Library;

    friend struct BookCollection;

    public:

    Book(const char* Name, const char* Author) : name_(Name), author_(Author){}

    void operator+=(const char* Page){

    pages_.push_back(Page);

    }

    void EditAuthor(const char* AuthorName){

    if(approve(AuthorName)){

    author_ = AuthorName;

    }

    else{

    std::ostringstream errorMessage;

    errorMessage <

    throw std::exception(errorMessage.str().c_str());

    }

    }

    void EditName(const char* Name){

    if(approve(Name)){

    name_ = Name;

    }

    else{

    std::ostringstream errorMessage;

    errorMessage <

    throw std::exception(errorMessage.str().c_str());

    }

    }

    virtual void Summarize(){

    std::cout <

    << pages_.size() << ((pages_.size() == 1) ?" page:" : ((pages_.size() > 0) ?" pages:" :" pages")) << std::endl;

    if(pages_.size() > 0){

    ListPages(std::cout);

    }

    }

    private:

    std::vector pages_;

    const char* name_;

    const char* author_;

    void ListPages(std::ostream& output){

    for(int i = 0; i < pages_.size(); ++i){

    output << pages_[i] << std::endl;

    }

    }

    };

    class FairyTale : public Book{

    public:

    FairyTale(const char* Name, const char* Author) : Book(Name, Author){}

    };

    struct BookCollection{

    friend class Library;

    BookCollection(const char* Name) : name_(Name){}

    virtual void operator+=(const Book& Book)try{

    Collection.push_back(&Book);

    }catch(const std::exception& e){

    std::ostringstream errorMessage;

    errorMessage << e.what() <

    throw std::exception(errorMessage.str().c_str());

    }

    virtual void operator-=(const Book& Book){

    for(int i = 0; i < Collection.size(); ++i){

    if(Collection[i] == &Book){

    Collection.erase(Collection.begin() + i);

    return;

    }

    }

    std::ostringstream errorMessage;

    errorMessage <

    throw std::exception(errorMessage.str().c_str());

    }

    private:

    const char* name_;

    Books Collection;

    };

    template struct FixedBookCollection : public BookCollection{

    FixedBookCollection(const char* Name) : BookCollection(Name){

    if(!isBook()){

    std::ostringstream errorMessage;

    errorMessage <

    throw std::exception(errorMessage.str().c_str());

    delete this;

    }

    }

    void operator+=(const FixedType& Book)try{

    Collection.push_back(&Book);

    }catch(const std::exception& e){

    std::ostringstream errorMessage;

    errorMessage << e.what() <

    throw std::exception(errorMessage.str().c_str());

    }

    void operator-=(const FixedType& Book){

    for(int i = 0; i < Collection.size(); ++i){

    if(Collection[i] == &Book){

    Collection.erase(Collection.begin() + i);

    return;

    }

    }

    std::ostringstream errorMessage;

    errorMessage <

    throw std::exception(errorMessage.str().c_str());

    }

    private:

    std::vector Collection;

    };

    template struct FixedSizeBookCollection : private std::array{

    FixedSizeBookCollection(const char* Name) : name_(Name){ if(Size < 1){ throw std::exception("A fixed size book collection cannot be smaller than 1"); currentPos = 0; } }

    void operator+=(const Book& Book)try{

    if(currentPos + 1 > Size){

    std::ostringstream errorMessage;

    errorMessage <

    throw std::exception(errorMessage.str().c_str());

    }

    this->at(currentPos++) = &Book;

    }catch(const std::exception& e){

    std::ostringstream errorMessage;

    errorMessage << e.what() <

    throw std::exception(errorMessage.str().c_str());

    }

    private:

    const char* name_;

    int currentPos;

    };

    class Library : private std::vector{

    public:

    void operator+=(const BookCollection& Collection){

    for(int i = 0; i < size(); ++i){

    if((*this)[i] == &Collection){

    std::ostringstream errorMessage;

    errorMessage <

    throw std::exception(errorMessage.str().c_str());

    }

    }

    push_back(&Collection);

    }

    void operator-=(const BookCollection& Collection){

    for(int i = 0; i < size(); ++i){

    if((*this)[i] == &Collection){

    erase(begin() + i);

    return;

    }

    }

    std::ostringstream errorMessage;

    errorMessage <

    throw std::exception(errorMessage.str().c_str());

    }

    Book* DuplicateBook(Book* Book)const{

    return (Book->Duplicate(*Book));

    }

    void Summarize(){

    std::cout < 0) ?" book collections:" :" book collections")) << std::endl;

    if(size() > 0){

    for(int i = 0; i < size(); ++i){

    std::cout << (*this)[i]->name_ << std::endl;

    }

    }

    }

    };

    至于ad-hoc多态,它意味着函数重载或运算符重载。点击这里:

    http://en.wikipedia.org/wiki/Ad-hoc_polymorphism

    对于参数多态,模板函数也可以计入,因为它们不一定采用FIXED类型的参数。例如,一个函数可以对整数数组进行排序,也可以对字符串数组进行排序等。

    http://en.wikipedia.org/wiki/Parametric_polymorphism

    不幸的是,虽然这是正确的,但这是误导性的。由于SFINAE规则,模板函数可以获得隐式约束 - 使用模板中的操作隐式地约束多态性 - 模板特化可以提供覆盖更通用模板的临时替代模板。因此,模板(默认情况下)提供无约束的参数多态,但没有强制执行 - 至少有两种方式可以变为约束或临时。

    事实上,你的例子 - 排序 - 意味着一个约束。排序仅适用于有序类型(即提供

    这是使用多态类的基本示例

    #include

    class Animal{

    public:

    Animal(const char* Name) : name_(Name){/* Add any method you would like to perform here*/

    virtual void Speak(){

    std::cout <

    }

    const char* name_;

    };

    class Dog : public Animal{

    public:

    Dog(const char* Name) : Animal(Name) {/*...*/}

    void Speak(){

    std::cout <

    }

    };

    int main(void){

    Animal Bob("Bob");

    Dog Steve("Steve");

    Bob.Speak();

    Steve.Speak();

    //return (0);

    }

    多态性意味着许多形式,因此它用于操作员在不同实例下的不同行为。多态性用于实现继承。例如,我们为类形状定义了一个fn draw(),然后可以实现绘制fn以绘制圆形,方形,三角形和其他形状。 (这是类形状的对象)

    如果有人对这些人说过CUT

    The Surgeon

    The Hair Stylist

    The Actor

    会发生什么?

    The Surgeon would begin to make an incision.

    The Hair Stylist would begin to cut someone's hair.

    The Actor would abruptly stop acting out of the current scene, awaiting directorial guidance.

    所以上面的表示显示了OOP中的多态(同名,不同行为)是什么。

    如果您要参加面试,面试官要求您告诉/展示我们所在的同一房间的多态性的实例,比如说 -

    答案 - 门/窗

    想知道怎么样?

    通过门/窗 - 一个人可以来,空气可以来,光可以来,雨可以来,等等。

    即一种形式的不同行为(多态)。

    为了更好地理解它,并以简单的方式使用上面的例子..如果你需要参考代码,请按照上面的答案。

    正如我上面提到的那样,为了更好地理解上面例子中使用的c ++中的多态性。这可能有助于更新鲜地实际理解和联系在面试时执行代码背后的意义或内容。谢谢!

    op问"c ++中的多态"。你的答案太抽象了。

    展开全文
    weixin_28481133 2021-07-05 03:39:26
  • weixin_36018419 2021-02-27 12:42:44
  • qq_53826699 2021-06-08 19:40:57
  • weixin_42404983 2021-02-12 19:42:18
  • weixin_39901439 2021-03-15 16:20:09
  • weixin_45947938 2021-06-02 15:58:24
  • weixin_36284062 2021-02-13 00:41:13
  • weixin_42515372 2021-02-26 15:42:13
  • weixin_39634351 2021-02-12 19:58:48
  • weixin_36026440 2021-03-09 07:24:21
  • weixin_32047493 2021-03-17 10:52:51
  • weixin_35931648 2021-03-04 03:26:02
  • weixin_30539081 2021-02-13 00:39:54
  • weixin_39582569 2021-02-12 09:33:32
  • weixin_36305686 2021-02-10 05:28:42
  • weixin_30520605 2021-02-13 00:39:56
  • weixin_29233333 2021-04-23 19:41:12
  • weixin_39712611 2021-02-26 15:42:56
  • weixin_33460449 2021-05-20 19:17:32
  • weixin_29499957 2021-04-08 12:16:49
  • weixin_28963585 2021-02-12 09:33:36
  • weixin_32267129 2021-03-05 15:09:39
  • weixin_30249151 2021-04-15 15:45:16
  • weixin_33218378 2021-04-27 09:50:50
  • weixin_34264495 2021-02-12 17:53:33

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 125,650
精华内容 50,260
关键字:

多态性是指