I'm making a game in C#. I created a base class Shape and seven other classes (Shape1, Shape2, ...) that inherit from Shape. In my main program I keep track of the shape currently in play by using
Shape Current;
Then I randomise its value to be equal to one of the shapes, for example:
Current = new Shape1()
The problem is, after I randomise I want to draw the shape with
Current.Draw()
Each shape has its own Draw function, and I want it to use that function specificly, and not the function in Shape. How can I do that?
The concept you are describing is called polymorphism (treating different object types as one).
In C#, you do this via the virtual, abstract and override keywords. In the base class, you mark the polymorphic method as either virtual or abstract, with the difference being abstract methods must be defined by derived classes:
public abstract void Draw();
Note that virtual methods must define a body, while abstract methods must not. Then in the derived class you define the same method with the override keyword:
public override void Draw()
{
//whatever implementation
}
For far more information, see MSDN
I must say #BradleyDotNet explained it very well, I'm just adding a practical example that may help to clarify the use of it.
Notice how I used all virtual, abstract and override keywords.
using System;
namespace ShapeExample
{
class Program
{
public static void Main(string[] args)
{
for (int i = 0; i < 20; i++)
{
var shape = GetRandomShape();
shape.Draw();
}
}
public static Random Random = new Random();
public static Shape GetRandomShape()
{
var d = Random.Next(3);
switch (d)
{
case 1:
return new Shape1();
case 2:
return new Shape2();
default:
return new Shape3();
}
}
}
public abstract class Shape
{
public virtual void Draw()
{
//Console.WriteLine("General Shape");
Console.WriteLine(" _");
Console.WriteLine(" / \\ ");
Console.WriteLine("/___\\");
}
}
public class Shape1 : Shape
{
public override void Draw()
{
//Console.WriteLine("I want a square instead");
Console.WriteLine(" ____");
Console.WriteLine("| |");
Console.WriteLine("|____|");
}
}
public class Shape2 : Shape
{
public override void Draw()
{
//Console.WriteLine("I want a complicated circle instead");
double r = 3.0;
double r_in = r - 0.4;
double r_out = r + 0.4;
for (double y = r; y >= -r; --y)
{
for (double x = -r; x < r_out; x += 0.5)
{
double value = x * x + y * y;
if (value >= r_in * r_in && value <= r_out * r_out)
{
Console.Write('*');
}
else
{
Console.Write(' ');
}
}
Console.WriteLine();
}
}
}
public class Shape3 : Shape
{
//I don't care how I look like, I'm using the regular shape drawing.
//but I have some particular info that is not part of a regular Shape
public int ParticularField { get; }
public Shape3()
{
ParticularField = -100;
}
}
}
Related
I have created an interface and then derived a class from it:
public interface Ishape
{
void draw();
int Number { get; set; }
}
class Circle : Ishape
{
public Circle(int a)
{
number = a;
}
public void draw()
{
Console.WriteLine("Circle.");
}
private int number;
public int Number
{
get
{
return number;
}
set
{
if (value < -5)
number = -5;
}
}
public int GetNumber()
{
return number;
}
}
class Program
{
static void Main(string[] args)
{
Circle a1 = new Circle(-6);
Console.WriteLine(a1.GetNumber());
Console.ReadLine();
}
}
As you can see, there is an autoproperty in the interface. I then decided to create a property in the new class that derived from the interface that would set the variable "number" to -5 if the value is less than -5. For some reason, the property does not seem to be working. Using the constructor, I set the value of the variable to -6, and the property did not change the value to -5. Why?
This is because you are setting number = a and not Number = a in your constructor. Try this:
public Circle(int a)
{
Number = a;
}
Your Number Property is never actually set.
In your Circle constructor, change number to Number.
public Circle(int a)
{
Number = a;
}
Also, if you intend to use GetNumber as your publicly available get (and nothing more), then I would advise that you change the access modifier for your Number property in your Circle class.
I have four errors that I am struggling with.
In the WriteLine block meant to print out the areas of the shapes, both places where the variable 'area' appears give the error message: "The name 'area' does not exist in the current context". The second problem is within the class Rectangle : GeometricFigure for 'ComputeArea', the error reads "'Rectangle.ComputeArea()' hides inherited member 'GeometricFigure.ComputeArea()'. Use the new keyword if hiding was intended." The last error is within the class Triangle : GeometricFigure and concerns 'Triangle' in the 'public Triangle(int x, int y)' expression. The error message reads "'Rectangle.ComputeArea()' hides inherited member 'GeometricFigure.ComputeArea()'. Use the new keyword if hiding was intended.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ShapesDemo
{
class Program
{
static void Main(string[] args)
{
Rectangle rec = new Rectangle(8, 10);
Square squ = new Square(11, 12);
Triangle tri = new Triangle(10, 20);
Console.WriteLine("Computed area is {0}" + "\n\n" + "Computed Triangle is: {1}" + "\n",
squ.ComputeArea(area), tri.ComputeArea(area));
}
}
abstract class GeometricFigure
{
public GeometricFigure(decimal sideA, decimal sideB)
{
this.height = sideA;
this.width = sideB;
}
protected decimal area;
protected decimal width;
protected decimal height;
public decimal Height
{
get
{
return height;
}
set
{
height = value;
ComputeArea();
}
}
public decimal Width
{
get
{
return width;
}
set { width = value; }
}
public decimal Area
{
get { return area; }
set { area = value; }
}
public void ComputeArea()
{
}
}
class Rectangle : GeometricFigure
{
public Rectangle(decimal sideA, decimal sideB) : base(sideA, sideB)
{
}
public void ComputeArea()
{
area = width * height;
WriteLine("The Area is" + width.ToString(), height.ToString());
}
static void Display(Rectangle rec)
{
}
}
class Square : GeometricFigure
{
static void Display(Square squ)
{
}
public Square(decimal sideA, decimal sideB) : base(sideA, sideA)
{
}
}
class Triangle : GeometricFigure
{
static void Display(Triangle tri)
{
}
public Triangle(int x, int y)
{
this.Width = x;
this.Height = y;
}
}
}
The name area doesn't exist so you can't use it. The Main() method doesn't have access to area. I think what you are trying to do is:
class Program
{
static void Main(string[] args)
{
Rectangle rec = new Rectangle(8, 10);
Square squ = new Square(11, 12);
squ.ComputeArea();
Triangle tri = new Triangle(10, 20);
tri.ComputeArea();
Console.WriteLine("Computed area is {0}" + "\n\n" + "Computed Triangle is: {1}" + "\n",
squ.Area, tri.Area);
Console.ReadLine();
}
}
But you have a bigger design problem as well. Using GeometricFigure base class is going to give you a lot of problems. I would get rig of it completely or use an interface instead. Also your Triangle needs to be:
public Triangle(decimal sideA, decimal sideB) : base(sideA, sideA)
{
this.Width = sideA;
this.Height = sideB;
}
The Microsoft docs have a good example of what your are attempting to accomplish here, generally you want to:
Abstract what is common(in this case its computing the area)
Specify what is not common in your concretes
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-define-abstract-properties
here is my code. I want to increase speed value with a.Quest() method. This method is in the first class. And the second class inherits from first class.
Increasing method is in second class but I use it in first class. That's what I'm trying to do. I don't want to write so much code in main.
However when I run the program, both a.Speed and b.Speed is equal to zero. I expect one of them to be 10. How can I fix that?
interface IElektroBeyin
{
int Speed{ get; set; } // Hız kontrolü
}
class AA : IElektroBeyin
{
public int Speed { get; set; }
public virtual void GetFaster() { }
public virtual void GetSlower() { }
public void Quest()
{
int x;
Console.WriteLine("Want to get faster ? 1- Yes");
x = Console.Read();
if (x == 1)
{
GetFaster();
}
}
}
class BB : AA
{
public override void GetFaster()
{
Speed += 10;
}
public override void GetSlower()
{
Speed -= 10;
}
}
static void Main(string[] args)
{
BB b = new BB();
AA a = new AA();
a.Quest();
Console.WriteLine(b.Speed);
Console.WriteLine(a.Speed);
Console.ReadLine();
}
}
}
AA a = new AA();
a.Quest();
AA.Quest() calls AA.GetFaster(), but this method is empty. That's why nothing happens when it is called. BB.GetFaster() is not called since it is in a derived class of AA. You probably want it to be the other way around.
Further, to get a number that a user enters, you can't use the return value of Console.Read(). Use int.Parse(Console.ReadLine()) or something similar.
I just made a class Shapes and an other 2 classes ('Triangle' & 'Square') which inherit from 'Shapes'.
public class Shapes
{
private int sides;
}
public class Triangle : Shapes
{
public void init()
{
int sides = 3;
throw new System.NotImplementedException();
}
}
public class Square : Shapes
{
public void init()
{
int sides = 4;
throw new System.NotImplementedException();
}
}
Code is designed using Classdiagram
Question: How should I call the class so that it shows how many sides does a shape has?
Thanks
You need a protected member sides which is used within the init-section of every shape:
public class Shapes
{
protected readonly int sides;
public int NumberOfSides { get { return sides; } }
}
public class Triangle : Shapes
{
public Triangle()
{
this.sides = 3;
}
}
public class Square : Shapes
{
public Square()
{
this.sides = 4;
}
}
As Farhad Jabiyev mentioned using constructors is the usual way to initialize a new instance (see my code above)
Now when you call Shape#NumberOfSides you get 3 for Triangle and 4 for Square:
Shape square = new Square();
int number = square.NumberOfSides();
You need to add a property on the class that has an accessor like this
public class Shapes
{
private int sides;
public int NumberOfSides { get { return sides; } }
}
Then you can go mySquare.NumberOfSides
In below example, i defined number field. This field will work as i wanted but it is not enough efficient to provide my expectations.
number value is fixed value for each class,number is not dependent instances and number support polymorphism. How can i do that ? Or is there another solution for not use unneccesary number field for instances ?
abstract class Main
{
public int number;
public virtual void dostuff(){
int x = number;
}
}
class Derived:Main
{
public ovverride void dostuff(){
int x = number;
}
}
You could just make the number a property and initialise is in each class constructor:
abstract class Main
{
public int number{get; private set;}
public void dostuff(){
int x = number;
}
}
class Derived:Main
{
public Derived()
{
number = 5; // Specific value for each derived class
}
public void dostuff(){
int x = number;
}
}
Looks like I got the wrong end of the stick -- you want to be able to set it statically per class type, which has already been answered.
You could make the property static and then add it to each class:
abstract class Main
{
public static int number;
public virtual void dostuff(){
int x = Main.number;
}
}
class Derived : Main
{
public static int number;
public overide void dostuff(){
int x = Derived.number;
}
}
Edit: I am a bit confused by your comments about polymorhism so i have added some more examples.
Main obj = new Derived();
obj.doStuff(); //This will use Derived.number; as doStuff is and overidden virtual method.
However if you do the following:
abstract class Main
{
public static int number;
public void dostuff(){
int x = Main.number;
}
}
class Derived : Main
{
public static int number;
public new void dostuff(){
int x = Derived.number;
}
}
Then you get different behaviour as below:
Main obj = new Derived();
obj.doStuff() // Will use Main.number
Derived obj2 = (Derived)obj;
obj2.doStuff() // Will use Derived.number
If you want some other kind of behaviour i havn't defined here please exaplin because i do not understand what you want.