Xia
Xia

Reputation: 166

C# Method arguments and Subclass Types

I started to learn C# but I am confused about something. Let's say I have a class and 2 subclasses. I have a method inside the parent class called Add(). But when I use this method with subclasses, since the method is asking for a "Toople" and not a "Vector" or a "Point", it gives me an error. How can I solve this issue? Is there a way to allow subclasses to be inserted into the method or should I create new methods for each different subclass? Thanks a lot.

using System;
namespace RayTracerChallange
{
    public class Toople
    {
        public float x, y, z, w;

        public Toople(float X, float Y, float Z, float W)
        {
            x = X;
            y = Y;
            z = Z;
            w = W;

        }
        public Toople Add(Toople Toop)
        {
            return new Toople(this.x + Toop.x, this.y + Toop.y, this.z + Toop.z, this.w + Toop.w);
        }

  public class Point : Toople
  {
      Point(float X, float Y, float Z) : base(X, Y, Z, 1)
      {
          this.x = X;
          this.y = Y;
          this.z = Z;
      }
  }

  public class Vector : Toople
  {
      Vector(float X, float Y, float Z) : base(X, Y, Z, 0)
      {
          this.x = X;
          this.y = Y;
          this.z = Z;
      }
  }

Upvotes: 0

Views: 813

Answers (2)

Christoph
Christoph

Reputation: 3642

I don't understand the context fully, but probably I would just have a single class Toople without the two others (Point and Vector) as they do not provide any additional functionality (or I would even use a struc as this seems to be about ray tracing where speed is usually crucial).

Then I would add some operators to handle the addition, something like this:

public struct Toople {

    Toople(float x, float y, float z, float w) {
        X = x;
        Y = y;
        Z = z;
        W = w;
    }

    public static Toople CreatePoint(float x, float y, float z) {
        return new Toople(x, y, z, 1);
    }

    public static Toople CreateVector(float x, float y, float z) {
        return new Toople(x, y, z, 0);
    }

    public Single X { get; }

    public Single Y { get; }

    public Single Z { get; }

    public Single W { get; }

    public static Toople operator +(Toople first, Toople second) {
        checked {
            return new Toople(first.X + second.X, first.Y + second.Y, first.Z + second.Z, first.W + second.W);
        }
    }

}

Upvotes: 0

Steve Czetty
Steve Czetty

Reputation: 6238

The closest you're going to get here is by making Toople generic and abstract, possibly by doing something like this:

using System;
namespace RayTracerChallange
{
    public abstract class ToopleBase<T> where T : ToopleBase<T>
    {
        public float x, y, z, w;

        protected Toople(float X, float Y, float Z, float W)
        {
            x = X;
            y = Y;
            z = Z;
            w = W;

        }
        protected abstract T MakeT(float X, float Y, float Z, float W);

        public T Add(Toople Toop)
        {
            return makeT(this.x + Toop.x, this.y + Toop.y, this.z + Toop.z, this.w + Toop.w);
        }
  }

  public class Toople : ToopleBase<Toople>
  {
      Toople(float X, float Y, float Z, float W) : base(X, Y, Z, W)
      {
      }

      Toople MakeT(float X, float Y, float Z, float W)
      {
          return new Toople(X, Y, Z, W);
      }
  }

  public class Point : ToopleBase<Point>
  {
      Point(float X, float Y, float Z) : base(X, Y, Z, 1)
      {
      }

      protected override Point MakeT(float X, float Y, float Z, float W)
      {
          return new Point(X, Y, Z);
      }
  }

  public class Vector : ToopleBase<Vector>
  {
      Vector(float X, float Y, float Z) : base(X, Y, Z, 0)
      {
      }

      protected override Point MakeT(float X, float Y, float Z, float W)
      {
          return new Vector(X, Y, Z);
      }
  }

A couple things to note:

  • I'm not sure why you would want to do this, it should be good enough to simply return the base class Toople if you are following the Liskov Substitution Principle. (That is, the rest of the application should be able to expect any subclasses to behave in the same way as their base class, and should not even have the knowledge that the subclasses exist.)
  • The constructors of the child classes don't need to set the fields in the parent class, since the parent class is already doing that.

Upvotes: 1

Related Questions