Editor not recognizing the existance of implemented methods 2021.3 LTS

OK, I’ve been working on a set of camera controls for simulation and strategy games, the idea being several swappable camera modes – a classic traditional mode (similar to Cities: Skylines), first person modes (similar to Minecraft creative mode), and variants with several discrete Y levels for things like stories in a building (thing of The Sims). To do this all camera controls (“modes”) extend an abstract class that acts as an interface with some common data attached. The problem is, some abstract methods are recognized while other give an error for not being implemented:

In the base class ACameraControl:

        /// <summary>
        /// This gets the position currently under under the cursor (center screen for first-person
        /// views).  This is intended for situations when some element most be moved constantly,
        /// such as an effected spot marker.  It needs to be nullable in case moved off the area.
        /// </summary>
        /// <returns></returns>
        public abstract Vector3? GetCursorLocation();


        /// <summary>
        /// This gets the game object currently under under the cursor (center screen for first-person
        /// views).
        /// </summary>
        /// <returns></returns>
        public abstract GameObject GetCursorObject();

…later in a derive class…

        public virtual Vector3? GetCursorLocation() {
            Ray ray = playerEye.ScreenPointToRay(Input.mousePosition);
            // Don't give a world position if on the UI
            if(Physics.Raycast(ray, out RaycastHit hit, float.PositiveInfinity, UILayer)) {
                return null;
            }
            if(Physics.Raycast(ray, out RaycastHit hit, playerEye.farClipPlane, groundPlainMask)) {
                return hit.point;
            }
            // Don't give a world position if somehow off screen or not pointing a ground plain
            return null;
        }


        public virtual GameObject GetCursorObject() {
            Ray ray = playerEye.ScreenPointToRay(Input.mousePosition);
            if(Physics.Raycast(ray, out RaycastHit hit, float.PositiveInfinity, UILayer)) {
                return null;
            }
            if(Physics.Raycast(ray, out RaycastHit hit, playerEye.farClipPlane, layerMask)) {
                return hit.collider.gameObject;
            }
            return null;
        }

Its there, plain as day, and my IDE sees it and thinks everything is good. But when returning to the Unity Editor I get errors flagged for this and every other derived class claiming that GetCursorObject() hasn’t been implemented, though it does recognize GetCursorLocation() as being implemented.

This is not the first time I’ve seen something like this happen, btw, just the latest. In the past re-arranging the order of the methods seemed to help, but not this time. I tried restarted the editor, in case it was stuck on some old data.

Is this a bug? – it sure looks like one. Otherwise, what is going on?

9412040–1318193–ACameraControl.cs (3.83 KB)
9412040–1318196–ClassicControl.cs (7.46 KB)

To implement abstract methods you need to use the override keyword. If you use the virtual keyword, the compiler treats them as new methods that hide the abstract methods declared in the parent class, since they have the same signature.

Thanks, that helped – but it is strange and confusing, why did it only give an error for one but not the other (no error at all until I added the second method).

Also, are abstract methods inherently virtual? Or is it just not possible for them to be virtual?

(I learned most of my programming skills in Java, which made C# easy at first, but trips me sometimes with subtle differences or C# features that Java lacks.)

EDIT: Nevermind, I googled and got the answer, thanks again.

Abstract and virtual methods are two different things, even though they are both overriden using the override keyword.

Abstract methods can only be defined in abstract classes and have no method body. They must be implemented (overridden) by derived classes.

Virtual methods can be defined in both abstract and non-abstract classes. They must have a method body (which can be empty). They can be overridden by derived classes, but it’s not mandatory.

Basically, an abstract method is saying “a derived class must provide its own implementation” and a virtual method is saying “a derived class may override the existing implementation”.

What I was asking was, can a class derived from the derived class override it again, as opposed to hiding it (making the overridden first implementation implicitly virtual – which is what Google claims). I understand that abstract classes have to overriden (I usually just say implemented, since they aren’t even implemented in the abstract original). I suppose this is an example of applying Java thinking, as Java has no virtual keyword (all methods being effectively virtual, so anything abstract must be “implement” in non-abstract “subclasses”).

The reason I was using virtual instead of override was because I wasn’t sure if I would be able to override it again if I needed to in potential grandchildren of the original abstract class if needed. (So far, there is only one grandchild, and it didn’t need to override that, but I wanted it be an option.)

Anyway, thank for the help, I think I understand what is going on and how to work with this now.

Well, yes and no ^^. Abstract methods are implicitly virtual. So you could view abstract methods as a special form of a virtual method. So they are the same thing, but for an abstract method (and therefore an abstract class) the pointer in the v-table is simply empty since no implementation is given. As long as the derived class stays abstract, even inherited abstract methods can stay abstract until you reach the first derived type that is not abstract. At this point all not-yet-filled spots in the vtable need to be filled.

So yes, you can further override your abstract method in more derived classes. The method doesn’t become a virtual method with the first implementation, it already is a virtual method, just without any implementation (yet). Note that C++ can work quite different in this regard as the C++ compiler in some cases can optimise away the need for a vtable and statically link everything. However this has more to do with what classes are actually exposed and may be related to the “final” keyword which is similar to C#'s “sealed” keyword. Though those two languages have completely different base so it’s hard to compare them.

So basically its the same as in Java, at the very least for practical purposes – the difference (which threw me off) being that in Java everything is effectively virtual, while C# allows (and defaults to) methods not being virtual. Since I didn’t know how this was handle “under-the-hood” by the compiler and IL interpreter, I went for declaring the implementations virtual, just in case.

I was never more than a beginner at C++, so most of my assumption come from Java (which I bordered on advanced with in the Java 7 days of a decade ago).

Anyway, thanks, its good to know the reasons for why things work the way they do and some of the gist of what is going on under the hood. So I learned a few different things today, and that is always good.