一个关于C#中基类与接口混合继承的疑问总结
思路参照 http://www.cnblogs.com/allenlooplee/archive/2004/11/16/64553.html,对原文进行了简化和补充,感谢原作者。
问题很简单,如下所示:
有如下接口声明:
interface IC
{
void M();
}
类A实现了接口IC:
class A : IC
{
public void M()
{
Console.WriteLine("In class A");
}
}
那么问题来了,如下两种声明类B的方式有什么区别:
class B : A
{ }
class B : A, IC
{ }
这个问题,我一直没弄明白,只好写一段代码来验证。
首先,对继承自A类的B进行改造,如下所示:
class B : A
{
void M()
{
Console.WriteLine("In class B");
}
}
结果编译器出现如下提示:
好吧,将代码改为:
class B : A
{
public new void M()
{
Console.WriteLine("In class B");
}
}
结果运行后结果竟然是In class A。。。
那下面这样行不行呢?
class B : A
{
void IC.M()
{
Console.WriteLine("In class B");
}
}
结果这回,编译器直接报错了。。。
好吧,看来,直接继承自A的类B,是无法修改M的行为的。下面来看另外一种方式实现的B。
class B : A, IC
{
public new void M()
{
Console.WriteLine("In class B");
}
}
运行结果如下图所示:
好了,这回没问题,同样,按照下面这种方式来写,结果也正常:
class B : A, IC
{
void IC.M()
{
Console.WriteLine("In class B");
}
}
所以,结论就很明显了。
1、如果B仅继承自A,那么接口的方法定就无法在B中被修改。
2、如果B同时继承自A和接口,那么可以在B中实现自己的方法。
其实,上述结论1中,还不算是太准确,有一种方法可以在B中实现自己的方法定义,如下所示:
首先,修改方法A:
class A : IC
{
public virtual void M()
{
Console.WriteLine("In class A");
}
}
然后,修改B的实现:
class B : A
{
public override void M()
{
Console.WriteLine("In class B");
}
}
这样,运行起来就可以得到预期的结果了。
注意,下面这种写法也是错误的,知道问题在哪里吗?
class B : A, IC
{
new void M()
{
Console.WriteLine("In class B");
}
}
一个关于C#中基类与接口混合继承的疑问总结的更多相关文章
- 关于Java中基类构造器的调用问题
在<Java编程思想>第7章复用类中有这样一段话,值得深思.当子类继承了父类时,就涉及到了基类和导出类(子类)这两个类.从外部来看,导出类就像是一个与基类具有相同接口的新类,或许还会有一些 ...
- 基类VS接口
该篇引用 CLR via C# 中的13.11节. 应该设计基类还是接口,这个问题不能一概而论,下面提供一些指导性原则: 1. IS_A关系(指属于,例如汽车属于交通工具) vs CAN_DO关系(指 ...
- C++中基类的析构函数为什么要用virtual虚析构函数
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅: C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是 ...
- C++中基类虚析构函数的作用及其原理分析
虚析构函数的理论前提是 执行完子类的析构函数,那么父类的虚构函数必然会被执行. 那么当用delete释放一个父类指针所实例化的子类对象时,如果没有定义虚析构函数,那么将只会调用父类的析构函数,而不会调 ...
- 详解C++中基类与派生类的转换以及虚基类
很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中 ...
- koa 基础(十八)es6中的类、静态方法、继承
1.app.js /** * es6中的类.静态方法.继承 */ // 定义Person类 class Person { constructor(name, age) { /*类的构造函数,实例化的时 ...
- koa 基础(十七)原生 JS 中的类、静态方法、继承
1.app.js /** * 原生 JS 中的类.静态方法.继承 * es5中的类和静态方法 */ function Person(name, age) { // 构造函数里面的方法和属性 this. ...
- C#编程语言与面向对象——抽象基类与接口
在一个类前加“abstract”关键字,此类就成为抽象类. 对应的,在一个方法前加“abstract”关键字,此方法就成为抽象方法. abstract class Fruit //抽象类 { publ ...
- 6、面向对象以及winform的简单运用(抽象基类与接口)
抽象类与抽象方法 1.书写规范: 在类前面加上abstract关键字,就成为了抽象类:在一个方法前面加上abstract关键字,就成为了抽象方法(抽象方法不能有实现方法,直接在后面加分号) 例: ab ...
随机推荐
- sql server 2008 R2 配置开启远程访问
- CI调试
- SQLServer 窗口函数
一.窗口函数的作用 窗口函数是对一组值进行操作,不需要使用GROUP BY 子句对数据进行分组,还能够在同一行中同时返回基础行的列和聚合列.窗口函数,基础列和聚合列的查询都非常简单. 二.语法格式 窗 ...
- Jsp servlet 值传递。。
先新建一个动态WEB项目. 展开WebRoot/index.jsp 1 <%@ page language="java" import="java.util.*&q ...
- Apache虚拟主机配置(多个域名访问多个目录)
Apache虚拟主机配置(多个域名访问多个目录) 为了方便管理虚拟主机,我决定使用一种方法,那就是修改httpd-vhosts.conf文件. 第一步首先要使扩展文件httpd-vhosts.conf ...
- iOS中僵尸对象的实现方法
什么是僵尸对象?所谓僵尸,就是过度释放的对象.在ios开发中,僵尸对象对于开发人员调试程序来说很有用.我们通常将NSZombieEnabled环境变量设置为YES来打开僵尸对象,但这会导致所有的对象都 ...
- Visitor
#include <iostream> #include <vector> using namespace std; #define DESTROY_POINTER(ptr) ...
- WebApi调试中遇到的一些问题
今天对WebApi的项目进行了一些调试,得到了一些教训,记录下来,也让大家少花些时间在这些无用功上面. (1)Fiddler 进行Post参数提交 刚开始,都是使用的Fiddler对服务进行调试,一直 ...
- Check Box Select/Deselect All on Grid
The below function is to be used on a grid with multiple check boxes. Place the code behind a FieldC ...
- 复杂的databinding接受Ilist作为数据源
Combobox控件绑定数据源时,List<T>可以作为数据源,但是List<String,Object> 不存在,我们有时候需要用Dictionary<String,o ...