C#继承问题

本文关键字:问题 继承 | 更新日期: 2023-09-27 17:57:32

我正在创建一个抽象基类,该基类具有由其他类实现的函数。我的疑虑如下

1) 我需要在每个需要由子类重写的函数前面给定"virtual"吗?我看到一些没有虚拟关键字的例子,但它们仍然可以被覆盖。

2) 我需要一个函数,它将在基类中实现,我不希望它被子类覆盖。我在该函数前面添加了"fixed"关键字。编译器开始抱怨不能密封"成员",因为它不是重写。我在这里做错了什么吗?

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;
        }

    };

C#继承问题

  1. 对于在抽象类中没有实现的方法,也可以使用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字段使用属性getter,而不是getShapeDetails()方法:

private ShapeDetails _shapedDetails;
public ShapeDetails ShapedDetails
{
    get { return _shapedDetails; }
}

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

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

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

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

关于第2点:你能添加使用固定词的代码吗?

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

不能覆盖非虚拟或静态方法。被覆盖的基础方法必须是虚拟的、抽象的或以(权力)否决


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

也可以使用密封修改器在重写的方法或属性上基中的虚拟方法或属性班这使您能够从您的类派生的类,以及阻止它们覆盖特定虚拟方法或属性。

只能覆盖虚拟方法,也只能实现抽象方法(如接口方法)。否则,某人只能声明一个新方法来"隐藏"旧方法,如下所示:

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. 如果希望在基类中提供可在派生类中重写的默认实现,则可以使用virtual keywork标记函数;或者您可以将其标记为abstract,将实现委派给派生类
  2. 如果您希望函数在子实现中不被覆盖,请不要将其标记为virtualabstract:只需像正常情况一样定义函数即可