2

I am new to C# and I am currently learning OOP. I am trying to learn how all these keywords work. I am learning the virtual keyword now and I made this class :

    // Animal class
    public class Animal
    {
        // Class propreties
        public string name { get; set; }
        public int age { get; set; }
        public double happiness { get; set; }

        public static int AnimalCounter = 0;

        // Class constructor
        public Animal(string name_ = "Spotty", int age_ = 4, double happiness_ = 3)
        {
            this.name = name_;
            this.age = age_;
            this.happiness = happiness_;
        } 

        // Virtual methods
        public virtual void Print() { }
        public virtual void Woof () { }
        public virtual void Meow () { }
    }

What I don't understand is why I can't write protected instead of public when I use virtual. For example at

public virtual void Print() {}

It gives me an error when I write

protected virtual void Print() {}

and as far as I know, protected means that the property can only be accessed in the base class and all the other classes that are made from the base class.

So I had a new class called : Dog that is made from the base class Animal

// Dog class
    public class Dog : Animal
    {
        /* Class Propreties */
        protected double SpotCount_ { get; set; }
        protected double woof_happinessIncrease_ { get; set; }

        // SpotCount = > get and set // GET returns SpotCount // SET 20 if bigger or equal to 20 . SET 0 if less or equal to 0 . otherwise set it to the given value
        public double SpotCount
        {
            get
            {
                return SpotCount_;
            }
            set
            {
                if(value >= 20)
                {
                    SpotCount_ = 20;
                }
                else if(value <= 0)
                {
                    SpotCount_ = 0;
                }
                else
                {
                    SpotCount_ = value;
                }
            }
        }
        // woof_happinessIncrease = > get and set // GET returns woof_happinessIncrease // SET 100 if bigger or equal to 100. SET 0 if less or equal to 0 . otherwise set it to the given value
        public double woof_happinessIncrease
        {
            get
            {
                return woof_happinessIncrease_;
            }
            set
            {
                if(value >= 100)
                {
                    woof_happinessIncrease_ = 100;
                }
                else if(value <= 0)
                {
                    woof_happinessIncrease_ = 0;    
                }
                else
                {
                    woof_happinessIncrease_ = value;
                }
            }
        }

        /* Class Constructor */
        public Dog(string name_ = "Spotty", int age_ = 4, double happiness_ = 3, double SpotCount_=3, double woof_happinessIncrease_=2) : base(name_, age_, happiness_)
        {
            this.SpotCount_ = SpotCount_;
            this.woof_happinessIncrease = woof_happinessIncrease_;
        }

        /* Class Override Methods */
        public override void Print()
        {
            Console.WriteLine(String.Format("Name : {0}", this.name.ToString()));
            Console.WriteLine(String.Format("Age : {0}", this.age.ToString()));
            Console.WriteLine(String.Format("Happiness : {0}", this.happiness.ToString()));
            Console.WriteLine(String.Format("Spot count : {0}", this.SpotCount.ToString()));

            Animal.AnimalCounter++; // Increase the animal counter size by 1 every time we have a new instance of the class Dog.
        }
        public override void Woof()
        {
            // Woof and increase happiness
            this.happiness += woof_happinessIncrease;
            Console.WriteLine(String.Format("{0} woofed. His happiness increased by {1}. His happiness now is : {2}", this.name.ToString(), this.woof_happinessIncrease.ToString(), this.happiness.ToString()));
        }
    }

I used override to override the methods that where virtual in the base class. But if I use protected in the base class for virtual methods it gives me an error.

Does anyone know why ?

COMPILE ERROR : CS0507 : 'function1' : cannot change access modifiers when overriding 'access' inherited member 'function2'

An attempt was made to change the access specification in a method override.

David
  • 624
  • 1
  • 6
  • 21
  • 8
    Q: Could you please update your post with the exact compile error? – FoggyDay Dec 13 '19 at 18:43
  • 9
    You have to make the override protected too, it's telling you that you can't change the access modifier (public, protected, private). If `Print` is protected it can't be made public on a subclass – Charleh Dec 13 '19 at 18:47
  • 3
    Because you're trying to change the contract defined by the base class. If the base class says something is public, it has to be public in derived classes. – Daniel Mann Dec 13 '19 at 18:47
  • 1
    You can do `protected virtual` but the base class has to have that field as `protected` as well. –  Dec 13 '19 at 18:48
  • 1
    If I change `Print()`, `Woof ()` and `Meow ()` to `protected virtual void` in the base class, and `protected override void` in the derived class, then your code compiles successfully. See https://dotnetfiddle.net/qvoqu6 – dbc Dec 13 '19 at 18:48
  • 1
    Ah OK if you are trying to make the derived methods "more public" than the overridden base methods, then you can't just do that, see [Why can't we change access modifier while overriding methods in C#?](https://stackoverflow.com/q/6236909) . See [How to increase the access modifier of a property](https://stackoverflow.com/q/886977) for one possible workaround. – dbc Dec 13 '19 at 18:53
  • Thank you for all the helpful comments. I figured it out. – David Dec 13 '19 at 20:22

1 Answers1

1

There should be no issues with a public virtual method.

Make sure that the base method is public virtual AND that the extending classes (which override the method) mark it as public virtual.

public class Animal
{
    public virtual void Print() { }
}

public class Cat : Animal
{
    public override void Print() { Console.WriteLine("Meow"); }
}

This is not supported:

public class Animal
{
    protected virtual void Print() { }
}

public class Cat : Animal
{
    public override void Print() { Console.WriteLine("Meow"); } // Base is protected, so this doesn't make sense.
}
Tom Faltesek
  • 2,768
  • 1
  • 19
  • 30