繁体   English   中英

C# inheritance 问题

[英]C# inheritance questions

我正在创建一个抽象基础 class ,它具有由其他类实现的功能。 我的疑惑如下

1)我是否需要在每个需要被子类覆盖的 function 前面给出“虚拟”? 我看到一些没有 virtual 关键字的示例,它们仍然可以被覆盖。

2)我需要一个 function 将在基础 class 中实现,我不希望它被子类覆盖。 我在 function 前面添加了“固定”关键字。 编译器开始抱怨“成员”不能被密封,因为它不是覆盖。 我在这里做错了吗?

abstract public class ShapeBase
    {
        private ShapeDetails _shapedDetails;

        public CampusCardBase(ShapeDetails shDetails)
        {
            _shapedDetails= shDetails;
        }

        public virtual void Draw();
        public virtual float getWidth();
        public virtual void Swap();
        public virtual void Erase();

        public sealed ShapeDetails getShapeDetails()
        {
            return _shapedDetails;
        }


    };
  1. 对于在抽象 class 中没有实现的方法,也使用abstract

     abstract public void Draw(); abstract public float getWidth(); abstract public void Swap(); abstract public void Erase();
  2. 默认情况下方法是不可覆盖的; 它们只允许在声明为abstractvirtualoverride时覆盖派生类(但不允许override sealed )。

    因此,除了public之外,您不需要给getShapeDetails()任何其他修饰符:

     public ShapeDetails getShapeDetails() { return _shapedDetails; }

附带说明一下,您应该坚持 .NET 命名约定并使用 Pascal 大小写大写方法名称,因此getWidth()变为GetWidth()并且getShapeDetails()变为GetShapeDetails()

实际上,您应该为_shapedDetails字段使用属性获取器,而不是getShapeDetails()方法:

private ShapeDetails _shapedDetails;

public ShapeDetails ShapedDetails
{
    get { return _shapedDetails; }
}

要被覆盖,必须将成员标记为虚拟或抽象。 如果是抽象的,则 class 也必须是抽象的,并且该成员在定义的 class 中没有实现。 虚拟成员必须提供实现。 派生类必须覆盖抽象成员并且可以覆盖虚拟成员。 非虚拟成员可能不会被“密封”,因为它们无论如何都不能被覆盖。

第 1 点:您可以将这些函数抽象为虚拟函数,而不是虚拟函数。

public abstract void Draw();
public abstract float getWidth();
public abstract void Swap();
public abstract void Erase();

这意味着必须覆盖那些 function。 目前,您可以在没有任何定义的情况下创建抽象 class 的子类,它仍然可以编译。 通过说这些是必须被覆盖的抽象函数。 如果您不覆盖,则子 class 也将是抽象的。

关于第2点:您可以添加使用固定词的代码吗?

1-引用覆盖(C# 参考)

您不能覆盖非虚拟或 static 方法。 被覆盖的基方法必须是虚拟的、抽象的或覆盖的。


2-引用密封(C# 参考)

您还可以在覆盖基础 class 中的虚拟方法或属性的方法或属性上使用密封修饰符。 这使您能够允许类从 class 派生,并防止它们覆盖特定的虚拟方法或属性。

如果是抽象方法,默认为虚方法,需要在继承class中实现。 否则,如果它不是抽象的,你需要有 virtual 关键字。 如果您不这样做,将使用编译时类型方法。

只能重写虚方法,只能实现抽象方法(如接口方法)。 否则,唯一能做的就是声明一种新方法来“隐藏”旧方法,如下所示:

new public void getShapeDetails() {
    // Hides base.getShapeDetails();
}

这是一个代码示例/说明。

//-----------------------------------------------------------------------------
// <copyright file="Program.cs" company="DCOM Productions">
//     Copyright (c) DCOM Productions.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------------

namespace AbstractClassExample {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    class Program {
        /// <summary>
        /// Example abstract base class
        /// </summary>
        public abstract class FooClass {

            /// <summary>
            /// Abstract Method
            /// </summary>
            public abstract void abstractFoo();

            /// <summary>
            /// Virtual Method
            /// </summary>
            public virtual void virtualFoo() {
                // Todo
            }

            /// <summary>
            /// Normal Method
            /// </summary>
            public void Foo() {
                // Todo
            }

        }

        public class FooDeriver : FooClass {
            /// <summary>
            /// Implements base.abstractFoo
            /// </summary>
            public override void abstractFoo() {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Overrides base.virtualFoo
            /// </summary>
            public override void virtualFoo() {
                base.virtualFoo();
            }

            /// <summary>
            /// Compiler ErrorError 1
            /// cannot override inherited member 'ConsoleApplication1.Program.FooClass.Foo()' because it is not marked virtual, abstract, or override
            /// </summary>
            public override void Foo() {
                throw new NotImplementedException();
            }
        }

        static void Main(string[] args) {
            // Program code
        }
    }
}
  1. 如果你想在你的基础 class 中提供一个可以在派生类中被覆盖的默认实现,你可以用virtual键标记 function; 或者您可以将其标记为abstract ,将实现委托给派生类。
  2. 如果您希望 function 不在子实现中被覆盖,请不要将其标记为virtualabstract :只需像往常一样定义 function 即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM