首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

当方法没有被重写时,为什么要使用“协变”?

在面向对象编程中,即使一个方法在子类中没有被显式地重写(重载),使用“协变”仍然有其合理性和优势,主要体现在以下几个方面:

协变的优势

  • 提高代码的灵活性和可扩展性:协变允许将子类型的实例赋值给父类型的引用或参数,这使得代码在处理不同类型的对象时更加灵活。
  • 增强代码的复用性:通过协变,可以编写通用的算法或函数,这些算法或函数能够接受不同子类型的参数并执行相同的操作,从而提高代码的复用性。
  • 遵循Liskov替换原则:协变有助于保持Liskov替换原则,即子类型可以替换父类型而不会导致错误,这增加了代码的稳定性和可靠性。

协变的应用场景

  • 多态性:在需要处理多个子类型的对象,并且希望使用通用的代码来处理它们时,协变提供了灵活的类型转换和操作。
  • 继承关系:在具有继承关系的类型之间,协变允许处理不同子类型的对象,而不需要进行显式的类型转换。
  • 泛型编程:在泛型编程中,协变可以用于处理泛型类型参数,使得泛型代码更好地适应不同子类型的需求。

为什么即使方法没有被重写,也需要考虑协变

即使子类中没有重写父类的方法,使用协变也是有意义的,因为它允许子类提供特定于其自身实现的同时,保持与父类方法的兼容性。这在面向对象设计中尤为重要,因为它支持多态性,即允许使用父类类型的引用来引用子类的对象,并在运行时根据实际类型调用正确的方法实现。这种机制确保了类型之间的安全转换和操作,同时保持了代码的灵活性和可扩展性。

相关搜索:当被调用的方法没有返回时,取消整个任务为什么当更新被调用(Pygame Pong)时,球没有移动?当使用Telethon for Telegram时,如何纠正“‘协程’对象没有属性‘数据’”错误?当类被添加到元素中时,为什么我的CSS没有被应用?在C++中使用成员函数的向量时,有没有办法实现协变返回类型?为什么当父节点甚至没有被更新时,子节点会被重新渲染?当类型被擦除时,隐式查找要通过泛型调用的正确方法是什么?当从选择框中选择一个项目时,为什么component类中的方法没有被调用?当reflect.Value被传递给golang中的接口时,为什么不能使用Pointer()方法?当使用ets()时,为什么R没有响应并崩溃?当href被点击时,有没有更好的方法来防止整个页面滚动?为什么我的处理程序方法在定义为lambda时没有被触发?当AutoGenerateColumns ="True"使用DataGrid时,为什么DataAnnotations <Display(Name:="My Name")>被忽略当使用导航器时,我如何解析方法'ancestorStateOfType‘在null上被调用?当没有<options>类型的标记被编码时,如何使用selenium点击DIV下拉值当字符串没有被特定字符包围时,使用空格拆分字符串当一个用户表单被卸载时,为什么相关的对象没有被设置为空?当没有设置responseType参数时,为什么下面被覆盖的方法返回Promise<HTTPResponse<Buffer>>?当一个链接被点击时,除了使用的方法'scroll top‘之外,还有什么替代方法吗?当更多的内存分配完成时,为什么程序使用的内存没有改变?
相关搜索:
页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

C#高级语法之泛型、泛型约束,类型安全、逆变和协变(思想原理)

一、为什么使用泛型?...:协变时泛型无法作为参数、逆变时泛型无法作为返回值。...逆变: ? 协变: ? 语法都是一些 非常粗糙的东西,重要的是思想、思想、思想。然后我们来看一下为什么要有逆变和协变? 什么叫做类型安全?...所以当逆变作为参数传递时,类型是安全的。 思考:那么,现在你能明白上面那个错误,为什么“协变时泛型无法作为参数、逆变时泛型无法作为返回值”了吗?...,但是实际上要返回的类型是Animal //所以就存在Animal类型转换为Dog类型,所以就有可能失败 //所以逆变时泛型无法作为返回值 T In(); void AddAnimal

7.1K30

编码最佳实践——里氏替换原则

(与代码中能被替换的类型有关) 子类型的方法参数必须是支持逆变的 子类型的返回类型必须是支持协变的 子类型不能引发不属于已有异常层次结构中的新异常 契约 我们经常会说,要面向接口编程或面向契约编程。...1.子类型不能加强前置条件 当子类重写包含前置条件的超类方法时,绝不应该加强现有的前置条件,这样做会影响到那些已经假设超类为所有方法定义了最严格的前置条件契约的客户端代码。...当有方法需要ICovariant的实例时,完全可以使用ICovariant的实例替代之。...因为不使用泛型类型,C#方法的返回类型就不是协变的。换句话说,这种情况下(普通类)的继承是不具备协变能力的。...C#语言的方法参数类型和返回类型都是不可变的,只有在设计泛型时才能将类型定义为可协变的或可逆变的。

1.3K20
  • 【C++篇】灵动之韵:C++多态之舞,赋予代码生命的艺术

    这也是为什么使用虚函数会引入一定的性能开销,因为需要通过 vptr 间接查找到虚函数的实际地址。...2.6 协变(Covariance) 在 C++ 中,派生类可以在重写基类虚函数时使用与基类虚函数返回类型不同的返回类型。这种返回值类型的变化被称为协变。...2.6.1 协变的定义 当派生类重写基类的虚函数时,如果基类虚函数返回基类对象的指针或引用,派生类重写后的虚函数可以返回派生类对象的指针或引用。这种返回值的变化称为协变(Covariance)。...2.6.2 协变的使用示例 协变通常用于在继承关系中,返回更加具体的派生类类型,从而让调用者能够获得更加明确的对象类型。...这种返回值类型的改变就是协变。 协变的优势在于,它允许我们在使用基类接口的同时,能够获得更加具体的派生类对象,从而提高代码的灵活性和类型安全性。

    19210

    方法重载与重写

    重写: 重写发生在子类与父类之间,子类重新定义了父类的方法。 重写要求子类按照父类被重写方法有相同的方法名、参数列表和返回类型。 不能存在同一个类中,在继承或实现关系的类中。 方法重载又可称为什么?...如果我们更改重载方法的返回类型,则将导致模棱两可的行为。 客户将如何知道哪种方法将返回哪种类型。 由于这种不同,重载方法中不允许使用不同的返回类型。 是否可以在Java中重载main()方法?...Java不允许覆盖静态方法。 如果在子类中创建一个具有相同名称的静态方法,则它是一个新方法,而不是覆盖的方法。 为什么Java不允许重写静态方法? 要重写方法,您需要一个类的实例。...方法覆盖发生在两个具有层次关系的类中。 3.方法重载中的参数必须不同。 方法覆盖中的参数必须相同。 4.方法重载是一个编译时概念。 方法重写是运行时概念。 Java中的协变返回类型是什么意思?...方法的协变返回类型是一种在子类中重写该方法时可以用“更窄”类型替换的方法。 假设类B是类A的子类。类A和类B中都有一个get()方法。

    1.2K21

    C++-带你走进多态(1)

    举个栗子:比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。 2....被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写  BuyTicker就是虚函数,要构成多态就必须完成虚函数的重写,而且必须通过基类的指针或者引用调用这个虚函数。  ...协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...有些选择题可能会出,虚函数重写的返回值类型不一定相同,协变就是一个例外。...如果使用基类的指针指向一个派生类,就会出现内存泄漏的情况,因为派生类的析构函数并没有调用。解决方法就是让派生类和基类的析构函数完成重写。

    6810

    3分钟快速搞懂Java的桥接方法

    协变返回类型 协变返回类型是指子类方法的返回值类型不必严格等同于父类中被重写的方法的返回值类型,而可以是更 "具体" 的类型。...在Java 1.5添加了对协变返回类型的支持,即子类重写父类方法时,返回的类型可以是子类方法返回类型的子类。...因为在JVM方法中,返回类型也是方法签名的一部分,而桥接方法的签名和其父类的方法签名一致,以此就实现了协变返回值类型。...类型擦除 泛型是Java 1.5才引进的概念,在这之前是没有泛型的概念的,但泛型代码能够很好地和之前版本的代码很好地兼容,这是为什么呢?...当一个子类在继承(或实现)一个父类(或接口)的泛型方法时,在子类中明确指定了泛型类型,那么在编译时编译器会自动生成桥接方法,例如: public class Parent { void

    32050

    C++新旅程:三大特性之多态

    那么在继承中要构成多态还有两个条件1. 必须通过基类的指针或者引用调用虚函数 2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写。...注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因 为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用 虚函数重写的两个例外...协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指 针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...因为我们是创建了父类指针指向子类对象,当我们delete时并不会调用子类的相关方法。这时在堆区的数据(new string(name))没有被释放掉会造成内存泄漏。怎么解决?...这说明在连接时出现了问题,因为在我们纯虚析构写完的时候他其实只是一个声明,并没有函数的具体实现。其实无论是虚析构还是纯虚析构,都需要有函数的具体实现。为什么?

    10910

    3分钟快速搞懂Java的桥接方法

    协变返回类型 协变返回类型是指子类方法的返回值类型不必严格等同于父类中被重写的方法的返回值类型,而可以是更 “具体” 的类型。...在Java 1.5添加了对协变返回类型的支持,即子类重写父类方法时,返回的类型可以是子类方法返回类型的子类。...**因为在JVM方法中,返回类型也是方法签名的一部分,而桥接方法的签名和其父类的方法签名一致,以此就实现了协变返回值类型。...类型擦除 泛型是Java 1.5才引进的概念,在这之前是没有泛型的概念的,但泛型代码能够很好地和之前版本的代码很好地兼容,这是为什么呢?...当一个子类在继承(或实现)一个父类(或接口)的泛型方法时,在子类中明确指定了泛型类型,那么在编译时编译器会自动生成桥接方法,例如: public class Parent { void

    78441

    【C++】多态

    举个栗子: 比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。...注意⚠: 在重写基类虚函数时,派生类的虚函数不加virtual关键字,也可以构成重写(可以认为继承后基类的虚函数被继承下来了在派生类中依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用 但是父类的...3.2 协变 虚函数重写的第二个例外: 派生类重写基类虚函数时,与基类虚函数返回值类型可以不同。...但是是有要求的: 基类虚函数必须返回基类对象的指针或引用,派生类虚函数必须返回派生类对象的指针或引用,我们把这种情况称为协变。...它定义了一组方法和行为,但并没有具体的实现细节。你可以把它看作是一个规范,告诉其他类应该有哪些方法,并且如何使用这些方法。

    12410

    解锁C++多态的魔力:灵活与高效的编码艺术(上)

    2.1.1 为什么需要基类指针或引用 在C++中,如果直接使用派生类对象,即使它重写了基类的虚函数,编译器仍然会使用静态绑定,即在编译时确定调用的函数版本。...,派生类的虚函数在不加 virtual 关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用。...返回类型的协变限制 虽然C++支持协变返回类型(即派生类的重写函数可以返回一个更具体的类型),但协变限制仅限于指针或引用类型。...即使Derived类想返回double,这种重写是不允许的,因为返回类型不是指针或引用,违反了协变的限制。...防止虚函数被重写:当你不希望派生类重写某个虚函数时,可以将该虚函数标记为final。

    15710

    c++进阶(c++里的多态)

    具体来讲就是去完成某个行为,当不同对象去完成时会产生不同的状态。 举个例子:比如买票这个行为,当普通人买票时,为全价买票;当学生买票时,为半价买票;军人买票时,为优先买票。...那么在继承中要构成多态还有两个条件: 1.必须通过基类的指针或者引用调用虚函数 2.被调用的函数必须是虚函数,且派生类必须对基类的虚函数重写 #include using namespace...1.协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回类型不同。...即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...反过来思考我们要达到多态,有两个条件,一个是虚函数覆盖,一个是对象的指针或引用调 用虚函数。反思一下为什么? 完

    8310

    【C++从小白到大牛】多态那些事儿(上)

    ,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因 为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用*/ /*void BuyTicket...协变(基类与派生类虚函数返回值类型不同)(了解 不重要) 协变,虚函数返回值可以不同,返回值要求必须是父子类关系的指针或者引用。...建议:两个虚函数都加上virtual 2.6 C++11 override 和 final final 关键字的两个作用: 其一是final修饰的类是最终类,不能被继承 注意实现一个类,这个类不能被继承还有一种方法...其二是修饰虚函数,表示该虚函数不能再被重写 override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译就会报错。...2.7重载、覆盖(重写)、隐藏(重定义)的对比 重载: 两个函数在同一作用域 函数名相同,参数不同 重写(覆盖) 两个函数分别在基类和派生类的作用域 函数名/参数/返回值都必须相同(协变例外) 两个函数都必须是虚函数

    10110

    【C++】多态

    ⽐如买票这个⾏为,当普通⼈买票时,是全价买票;学⽣买票时,是优惠买票(5折或75折);军⼈买票时是优先买票。...注意:在重写基类虚函数时,派⽣类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派⽣类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使⽤,不过在考试选择题中...这里符合多态的条件,所以会重写,本质重写虚函数的实现 注意:当基类中的函数被声明为 virtual,这个特性会被继承到所有派生类。派生类中的相同函数会自动成为虚函数。...2.1.5 虚函数重写的⼀些其他问题 协变(了解) 派⽣类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引⽤,派⽣类虚函数返回派⽣类对象的指针或者引⽤时,称为协变。...协变的实际意义并不⼤,所以我们了解⼀下即可。

    6000

    【C++深度探索】全面解析多态性机制(一)

    通俗来说,就是多种形态,或者说完成某个行为时,当不同的对象去完成会产生出不同的状态。 例如:买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。...在继承中要构成多态有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 例如: class Person { public: virtual...4.虚函数重写的两个例外 协变(基类与派生类虚函数返回值类型不同) 即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...前面我们学习过虚函数重写必须要求基类与派生类除了函数体以外其它完全相同,但是对于协变,基类与派生类的返回值类型可以不同,但基类与派生类的函数的返回类型必须是继承关系 //协变 class A {};...结果如下: 这里要注意派生类的析构调用完之后会自动调用基类对象的析构函数,所以这里基类的析构函数调用了两次 我们可以对比一下,当没有实现多态时,对于delete对象调用析构函数是不会根据所指向的对象调用相应的析构函数

    12710

    【C++】———— 多态

    二、多态的定义和实现 1.多态构成条件 在继承中要形成多态还有两个条件: 调用时必须要通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须含有对基类的虚函数的重写 这里我们插入一个概念...权限要求不同:重载对访问权限没有要求,重写要求子类中的重写函数不能比父类中的被重写函数有更严格的访问权限。 与虚函数的关系:重载与虚函数无关,重写的函数通常是父类中的虚函数。...,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样写 2.虚函数的重写和协变 上面例子中...虚函数重写的两个例外: 2.1协变 派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指 针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...,分别在基类和派生类 4.final 和 override 添加在父类虚函数后面添加final代表不能再被重写 final修饰类,代表不能被继承: override代表必须要重写虚函数,如果没有重写便会报错

    11510

    【C++学习篇】 多态

    ⽐如买票这个⾏为,当普通⼈买票时,是全价买票;学⽣买票时,是优惠买票(5折或75折);军⼈买票时是优先买票。...注意:在重写基类虚函数时,派⽣类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派⽣类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使⽤,不过在考试选择题中...输出 1(val=1) B->1 2.1.5虚函数重写的⼀些其他问题 (一些例外) 2.1.5.1 协变 派⽣类重写基类虚函数时,与基类虚函数返回值类型不同。...即基类虚函数返回基类对象的指针或者引⽤,派⽣类虚函数返回派⽣类对象的指针或者引⽤时,称为协变。协变的实际意义并不⼤,所以我们了解⼀下即可。...,只有在程序运⾏时没有得到预期结果才来debug会得不偿失,因此C++11提供了override,可以帮助⽤⼾检测是否重写。

    8210

    【C++之剑】我不允许你还不会多态

    举个栗子:比如买票这个行为 ,当 普通人 买票时,是全价买票; 学生 买票时,是半价买票; 军人买票时是优先买票。...支付宝首先会分析你的账户数据,比如你是新用户、比如你没有经常支付宝支付等等,那么你需要被鼓励使用支付宝,那么就你扫码金额 =random()%99;比如你经常使用支付宝支付或者支付宝账户中常年没钱,那么就不需要太鼓励你去使用支付宝...协变 ( 基类与派生类虚函数返回值类型不同 ) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。...即基类虚函数返回基类对象的指 针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...反过来思考我们要达到多态,有两个条件,一个是虚函数覆盖,一个是对象的指针或引用调用虚函数。反思一下为什么? 5.

    7810

    为什么要把类设置成密封?

    性能优势 虚方法调用 在上面提到的文章例子中,有一个虚方法的调用,大家其实要明白一点,现在面向对象的封装、继承、多态中的多态实现主要就是靠虚方法。...一个类型可能会有子类,子类可能会重写类型的方法从而达到不同的行为(多态),而这些重写的方法都在虚方法表里,调用的话就需要查表。.... // 它可能已经被另一个方法设置为派生类。 // 所以,为了安全起见,它必须使用一个虚拟调用。...我们可以看到 JIT 生成后的汇编代码,可以很清楚的看到密封类少了两条指令,因为 JIT 可以从密封类中知道它不可能被继承,也不可能被重写,所以是直接跳转到密封类目标方法执行,而非密封类还有一个查表的过程...IL 层面,两个方法都是一模一样: 可以看到密封类的代码相当高效,直接比较一下就转换类型返回了,而非密封类还需要 call 方法走查表流程: 数组 .NET 的数组是协变的,协变兼容的话就意味着在添加进入数组时需要检查它的类型

    33620
    领券