2017-02-05 5 views
2

Я немного новичок в наследовании на C#. У меня есть два класса Velocity.cs и Position.cs, которые наследуют от базового класса Vector.cs. Я пытаюсь создать метод subtract() внутри Vector.cs, который будет доступен от Velocity.cs и Position.cs.C# Тип наследования Ошибка кастинга

Вот код для вычитания.

 public Vector subtract(Vector v) { 
     double nx = this.x - v.x; 
     double ny = this.y - v.y; 
     double mag = Math.Sqrt(x * x + y * y); 
     double ang = Math.Atan2(y, x); 
     return new Vector(mag, ang); 
    } 

код, определяющий Velocity.cs класс ниже.

class Velocity : Vector{ 

    public Velocity(Position p1, Position p2, double vpref) : base(p1, p2) { 
     normalize(); 
     scale(vpref); 
    } 

    public Velocity(double vmax) : base(new Random().NextDouble()*vmax, new Random().NextDouble()*2*Math.PI) { 

    } 

    public void change(Velocity v) { 
     x = v.x; 
     y = v.y; 
     magnitude = Math.Sqrt(x * x + y * y); 
     angle = Math.Atan2(y, x); 
    } 

} 

}

Когда я пытаюсь вызвать функцию Subtract снаружи, что-то вроде этого:

 Velocity v1 = new Velocity(5); 
     Velocity v2 = new Velocity(7); 
     Velocity result = v1.subtract(v2); 

Я получаю сообщение об ошибке говорящее Не можете явно конвертировать между 'Velocity' и 'Вектор' Вы забыли бросок?

Так что я попытался Velocity result = (Velocity)v1.subtract(v2); однако, что приводит к следующей ошибке: необработанного исключения типа «System.InvalidCastException» произошло

Как я могу переписать эту функцию, чтобы сделать эту работу? Должен ли я действительно делать три версии функции с типами возврата VectorVelocity и Position? Если да, то в чем смысл наследования? Я мог бы просто поместить их в свой класс.

Примечание: Я знаю, что класс скорости немного мал и может казаться бессмысленным в то время, я добавлю его позже, я в середине проекта.

+1

Примечание стороны, не do 'new Random() ..., new Random() ...'. Вместо этого создайте статический экземпляр класса Random и используйте его вместо этого. В противном случае вы получите тот же номер довольно часто. – pinkfloydx33

+0

Кроме того, ваш метод вычитания возвращает «Вектор». Вы пытаетесь присвоить его переменной типа «Velocity». Хотя верно, что 'Velocity' является« Vector »,« Vector »не обязательно является« Velocity »(это может быть« Позиция »). Вы всегда можете выполнить «Вектор-результат = v1.subtract (v2);», но вы будете иметь доступ к общим полям, определенным в «Вектор», которые могут быть или не быть достаточными в зависимости от вашего варианта использования. Другая сторона примечания: в соответствии с соглашениями об именах C# имена методов должны начинаться с заглавной буквы, т.е. 'Change (...)' и 'Subtract (...)'. – pinkfloydx33

+0

Я вижу, вам понравился подход первого ответчика. BTW двойная проверка шахты ... Я считаю, что она соответствует тому, что вы хотите более простым способом. –

ответ

1

А я вижу, что здесь происходит. Таким образом, ваша функция вычитания возвращает объект Vector, но C# не имеет способа разрешить вектор обратно в скорость.Я ударил это в прошлом, прежде чем получил его вокруг конструкторов копирования.

Так что в вашем классе: Вектор

public class Vector 
{ 
    /// <summary> 
    /// Copy Constructor 
    /// </summary> 
    /// <param name="toCopy"> 
    /// The vector object to copy 
    /// </param> 
    public Vector(Vector toCopy) 
    { 
     if (toCopy == null) 
     { 
      throw new ArgumentNullException("toCopy"); 
     } 

     x = toCopy.x; 
     y = toCopy.y; 
     //What ever other properties you have, assign them here 
    } 
} 

Тогда в классе Velocity:

public class Velocity : Vector 
{ 
    public Velocity(Vector vector) 
     : base(vector) 
    { 
    } 
} 

Наконец, как это будет использоваться:

Velocity result = new Velocity((v1).subtract(v2)); 
-2

Вы не можете кодировать три версии. Вы можете ввести общую функцию.

public T Substract<T> (T vector) where T: Vector 
{ 
    ... 
    return new T(...); // Edited to demonstrate last line as asked from comment 
} 
+1

Это имеет смысл, но как будет выглядеть эта последняя линия? 'return new T (mag, ang);' – ryanmattscott

+0

Это очень хороший ответ. –

+0

@ MatíasFidemraizer Я все еще делаю что-то не так. Это неверно: «return T где T: Vector, new (mag, ang);' – ryanmattscott

-1

Пожалуйста, обратите внимание, что ваш код

Velocity result = (Velocity)v1.subtract(v2); 

не отбрасывает результат вычитания метода к типу Velocity. Правильный способ сделать это:

Velocity result = (Velocity)(v1.subtract(v2)); 
+0

№. Это будет то же самое и не решает его/ее проблему. –

+0

Этот комментарий неверен. Кое-что вида '(T) v.s (u)' уже рассматривается как '(T) (v.s (u))', а не как '((T) v) .s (u)', как вы, кажется, думаете. Таким образом, дополнительная скобка хороша, но не требуется, поэтому ваш комментарий неверен. –

2

Я считаю, что Vector класс должен принимать параметр универсального типа, чтобы он знать тип его производного класса:

public class Vector<TImpl> where TImpl : Vector 
{ 
    public TImpl Subtract(TImpl v) 
    { 
     double nx = this.x - v.x; 
     double ny = this.y - v.y; 
     double mag = Math.Sqrt(x * x + y * y); 
     double ang = Math.Atan2(y, x); 

     return (TImpl)Activator.CreateInstance(typeof(TImpl), new object[] { mag, ang }); 
    } 
} 

public class Velocity : Vector<Velocity> 
{ 
} 

BTW, я чувствую, что Subtract метод должен быть методом расширения и все будет казаться менее странным:

public static class VectorExtensions 
{ 
     public static TImpl Subtract<TImpl>(this TImpl vectorImpl, TImpl other) 
      where TImpl : Vector 
     { 
     double nx = this.x - v.x; 
     double ny = this.y - v.y; 
     double mag = Math.Sqrt(x * x + y * y); 
     double ang = Math.Atan2(y, x); 

     return (TImpl)Activator.CreateInstance(typeof(TImpl), new object[] { mag, ang }); 
     } 
} 

... и вы будете в состоянии т o достигают цели:

Velocity result = v1.Subtract(v2); 
+0

Использование '(TImpl) Activator.CreateInstance (typeof (TImpl), новый объект [] {mag, ang})' выглядит уродливо для меня. –

+0

@JeppeStigNielsen Дайте мне альтернативу, и я улучшу фрагмент: D –

+0

@JeppeStigNielsen Альтернативой будет использование неявной реализации интерфейса, чтобы иметь возможность устанавливать некоторые свойства, не делая их общедоступными ... –

Смежные вопросы