深入浅出OOP(四): 多态和继承(抽象类)

在本文中,我们讨论OOP中的热点之一:抽象类。抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样。本文中我们会通过代码来实现抽象类,并一一进行解析。

Abstract Classes

在微软的MSDN中,对抽象类有如下的定义:

用abstract 关键字可定义抽象类,要求其子类必须实现抽象类的函数、属性等。抽象类不可被实例化。抽象类提供了统一的定义,用于其不同子类直接共享数据、函数。 抽象类也可定义抽象函数。

 

Abstract Classes实战

在Visual Studio中添加Console程序,并命名为“InheritanceAndPolymorphism”,添加ClassA.cs,添加抽象类ClassA。

using System;

namespace InheritanceAndPolymorphism
{
    public abstract class ClassA
    {

    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassA classA = new ClassA();
            Console.ReadKey();
        }
    }
}

编译报错:

Compile time error: Cannot create an instance of the abstract class or interface 'InheritanceAndPolymorphism.ClassA'

结论:无法用new关键字来实例化一个抽象类。

 

Abstract Class的非抽象函数

给抽象类ClassA添加一些非抽象函数的代码:

    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

        }
    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassA classA = new ClassA();
            Console.ReadKey();
        }
    }

 

编译,依然报错。 抽象类无论是否有抽象、非抽象函数,均无法通过new关键字来实例化。

 

Abstract Class作为基类

我们把抽象类作为基类,添加ClassB—使之继承自ClassA。

    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

        }
    }

    /// <summary>
    /// Derived class.
    /// Class derived from abstract class ClassA
    /// </summary>
    public class ClassB:ClassA
    {

    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            Console.ReadKey();
        }
    }

编译的结果:不再报错。

结论:一个类可以继承自abstract 修饰的抽象类,且可被new关键字初始化。

 

Abstract Class的非抽象函数声明

在ClassA中声明YYY函数--无函数体。

    /// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

        }

        public void YYY();
    }

    /// <summary>
    /// Derived class.
    /// Class derived from abstract class ClassA.
    /// </summary>
    public class ClassB:ClassA
    {

    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            Console.ReadKey();
        }
    }

 

编译,结果报错:

Compile time error: 'InheritanceAndPolymorphism.ClassA.YYY()' must declare a body because it is not marked abstract, extern, or partial

 

结论是需要对YYY添加函数体,或者添加abstract的修饰符。

 

Abstract Class的抽象函数声明

在ClassA的YYY前,添加abstract修饰符。

/// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

        }

       abstract public void YYY();
    }

    /// <summary>
    /// Derived class.
    /// Class derived from abstract class ClassA.
    /// </summary>
    public class ClassB:ClassA
    {

    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            Console.ReadKey();
        }
    }

 

编译结果,报错:

Compiler error: 'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()'

结论:我们在abstract 类中声明了一个abstract 的函数,但是并未在其子类ClassB中实现其内容;当使用new关键字初始化ClassB的时候则会报错----无法使用new关键字初始化一个abstract类。

 

子类继承实现抽象函数

在子类中添加YYY的实现。

/// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

        }

       abstract public void YYY();
    }

    /// <summary>
    /// Derived class.
    /// Class derived from abstract class ClassA.
    /// </summary>
    public class ClassB:ClassA
    {
        public void YYY()
        {

        }
    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            Console.ReadKey();
        }
    }

编译结果,报错:

Compile time error: 'InheritanceAndPolymorphism.ClassB' does not implement inherited abstract member 'InheritanceAndPolymorphism.ClassA.YYY()' Compile time warning: 'InheritanceAndPolymorphism.ClassB.YYY()' hides inherited member 'InheritanceAndPolymorphism.ClassA.YYY()'.

结论:要使得子类继承基类的YYY函数,需要用到override关键字,然后才可以用new关键字实例化ClassB。

 

非抽象类的抽象函数

我们再看看这些代码:

/// <summary>
    /// Abstract class ClassA
    /// </summary>
    public class ClassA
    {
        public int a;
        public void XXX()
        {

        }

       abstract public void YYY();
    }

    /// <summary>
    /// Derived class.
    /// Class derived from abstract class ClassA.
    /// </summary>
    public class ClassB:ClassA
    {
        public override void YYY()
        {

        }
    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            Console.ReadKey();
        }
    }

 

编译,结果报错:

Compiler error: 'InheritanceAndPolymorphism.ClassA.YYY()' is abstract but it is contained in non-abstract class 'InheritanceAndPolymorphism.ClassA'

结果分析:声明abstract的函数,必须同时声明类为abstract。

        abstract 的函数不能同时添加static或virtual关键字。

 

抽象基类函数

 

/// <summary>
    /// Abstract class ClassA
    /// </summary>
    public abstract class ClassA
    {
        public int a;
        public void XXX()
        {

        }

       abstract public void YYY();
    }

    /// <summary>
    /// Derived class.
    /// Class derived from abstract class ClassA.
    /// </summary>
    public class ClassB:ClassA
    {
        public override void YYY()
        {
             base.YYY();
        }
    }

    /// <summary>
    /// Program: used to execute the method.
    /// Contains Main method.
    /// </summary>
    public class Program
    {
        private static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            Console.ReadKey();
        }
    }

编译,结果报错:

Compile time error : Cannot call an abstract base member: 'InheritanceAndPolymorphism.ClassA.YYY()'

结果分析:ClassB中无法使用base调用基类的abstract函数--因为其不存在。

 

最后一个问题,可否在抽象类中添加sealed关键字,结果是不可以。

抽象类不能添加sealed、static类修饰符的。

 

结论

通过下面几点,归纳一下本文的结论。

  • 无法使用new来实例化abstract 抽象类
  • abstract 抽象类可以有子类,其子类实现抽象方法后,可被new实例化对象
  • 如声明了abstract 的函数,则必须声明abstract 的类
  • 当override抽象基类,无法修改基类函数的签名
  • abstract函数,无法同时添加static、virtual关键字
  • abstract 类无法被声明为sealed、static类

 

原文链接:Diving in OOP (Day 4): Polymorphism and Inheritance (All About Abstract Classes in C#)

时间: 2024-10-25 13:46:28

深入浅出OOP(四): 多态和继承(抽象类)的相关文章

深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)

访问修饰符(或者叫访问控制符)是面向对象语言的特性之一,用于对类.类成员函数.类成员变量进行访问控制.同时,访问控制符也是语法保留关键字,用于封装组件. Public, Private, Protected at Class Level 在创建类时,我们需要考虑类的作用域范围,如谁可访问该类,谁可访问该类成员变量,谁可访问该类成员函数. 换而言之,我们需要约束类成员的访问范围.一个简单的规则,类成员函数.类成员变量之间可以自由 访问不受约束,这里主要说的是外部的访问约束.在创建class的时候,

深入浅出OOP(六): 理解C#的Enums

MSDN定义:枚举类型(也称为枚举)为定义一组可以赋给变量的命名整数常量提供了一种有效的方法.  例如,假设您必须定义一个变量,该变量的值表示一周中的一天. 该变量只能存储七个有意义的值. 若要定义这些值,可以使用枚举类型.枚举类型是使用 enum 关键字声明的.   从OOP上来说,枚举的角色和和class一样,它创建了一种新的数据类型. 1: namespace Enums 2: { 3: class Program 4: { 5: static void Main(string[] arg

eclipse 为何没有自动提示对象(实现接口同时继承抽象类)的所有方法?

问题描述 eclipse 为何没有自动提示对象(实现接口同时继承抽象类)的所有方法? PS: 其他普通对象(例如 String 对象)有提示对象的所有方法. public interface BaseDao { ... } public abstract class BaseDaoImpl implements BaseDao {... } public interface BookDao extends BaseDao {... } public class BookDaoImpl exten

java 抽象类 继承-抽象类的继承问题&amp;amp;lt;新手求解&amp;amp;gt;

问题描述 抽象类的继承问题<新手求解> abstract class Person{} class Student extends Person{} 为什么Student s = new Student(); 能实例化成功. 子类Student是抽象类么? 不是没有重写方法么.... 解决方案 抽象类不能实例化,即不能直接new抽象类,必须是实例化一个抽象类的子类.可以定义一个抽象类的变量,但它的赋值必须是它的实现类,就是你给出的这段代码了. 解决方案二: 跟抽象类有关的问题继承 抽象类 解决

类模拟及多态、继承

在面向对象的语言里面,出现了类的概念.这是编程思想的一种进化.所谓类:是对特定数据的特定操作的集合体.所以说类包含了两个范畴:数据和操作.而C语言中的suct仅仅是数据的集合.(liyuming1978@163.com) 1.实例:下面先从一个小例子看起 #ifndef C_Class #define C_Class suct #endif C_Class A { C_Class A *A_this; void (*Foo)(C_Class A *A_this); int a; int b; }

PHP 面向对象程序设计(oop)学习笔记(一) - 抽象类、对象接口、instanceof 和契约式编程_php实例

1.PHP中的抽象类 PHP 5 支持抽象类和抽象方法.定义为抽象的类不能被实例化.任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的.被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现.在类的声明中使用 abstract 修饰符可以将某个类声明为抽象的. 可以这样理解,抽象类作为一个基类,它把特定的细节留给继承者来实现.通过抽象概念,可以在开发项目中创建扩展性很好的架构. 复制代码 代码如下: abstract class Abstrac

java用接口、多态、继承、类计算三角形和矩形周长及面积的方法_java

本文实例讲述了java用接口.多态.继承.类计算三角形和矩形周长及面积的方法.分享给大家供大家参考.具体如下: 定义接口规范: /** * @author vvv * @date 2013-8-10 上午08:56:48 */ package com.duotai; /** * * */ public interface Shape { public double area(); public double longer(); } /** * @author vvv * @date 2013-8

(一三八)多态公有继承

假如一个类继承另一个类,但有一个类方法,在不同类中,其行为是不同的. 换句话说,方法的行为,应取决于调用该方法的对象.这种较复杂的行为称为 多态--具有多种形态,即同一种方法的行为,随上下文而异.   有两种重要的机制可用于实现多态公有继承: ①在派生类中重新定义基类的方法: ②使用虚方法. 注:这两种机制共同使用       虚方法的关键字是:virtual 例如:virtual void show(); 虚方法的关键字,不在类外部使用,例如.cpp文件中的方法定义   虚方法的作用在于: 在

深入浅出OOP(一): 多态和继承(早期绑定/编译时多态)

在本系列中,我们以CodeProject上比较火的OOP系列博客为主,进行OOP深入浅出展现. 无论作为软件设计的高手.或者菜鸟,对于架构设计而言,均需要多次重构.取舍,以有利于整个软件项目的健康构建,有些经验是前辈总结的,我们拿来使用即可,有些是团队知识沉淀的,总之复用前人好的思想有利于减少返工.当然,在面试的时候,如果能围绕OOP大谈特谈,自然会加分多多的. 开始阅读本系列博客的预备知识,多态.封装.面向对象编程等,请通过MSDN学习.如下图的术语,您应该耳熟能详的.本系列文章使用C#作为唯