1

In the following example I am using C#.

I have created an abstract class Base_Collection, and then I derive other classes from it (Book, Movie, Game). However, I don't know how to add new methods that can be used for those new children classes without getting a compiler error.

namespace polymorphism_test_01
{
    abstract class Base_Collection
    {
        public int id = 0;
        public string title = "";

        public Base_Collection() { }
    }
}    

namespace polymorphism_test_01
{
    class Book : Base_Collection
    {
        public Book() { }

        public override void Read_Book() { }
    }
}    

namespace polymorphism_test_01
{
    class Game : Base_Collection
    {
        public Game() { }

        public void Play_Game() { }
    }
}   

namespace polymorphism_test_01
{
    class Movie : Base_Collection
    {
        public Movie() { }

        public void Watch_Movie() { }
    }
}

Calling book.Read_Book() doesn't work in the following snippet, the compiler will output an error:

namespace polymorphism_test_01
{
    class Program
    {
        public static void Main(string[] args)
        {
            Base_Collection book = new Book();

            book.title = "The Dark Tower";
            book.Read_Book();

            Console.WriteLine(book.title);
            Console.Write("Press any key to continue . . . ");
            Console.ReadKey(true);
        }
    }
}
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
TheScholar
  • 2,527
  • 5
  • 23
  • 25
  • The reason you are getting a compiler error is because you are creating a `Book` object and casting it as its base type. When you try to call `Read_Book()` on it this will not work because there is no `Read_Book()` defined on the `Base_Collection` type. `Read_Book()` is only defined on the `Book` type. You will fix your compiler error by creating your book as `Book book = new Book();` and also removing the `override` keyword from your `Read_Book()` method definition. – Ian R. O'Brien Dec 09 '12 at 02:02

5 Answers5

3

You are able to add methods to a base class without any problem. The reason you're getting a compiler error is because you used the override keyword incorrectly.

In order to use the override keyword the method name and signature must match the method name and signature in the parent class, and method must be marked as virtual or abstract in the base class. The difference between the two is answered here.

Since the book, movie, and film can all be "performed", you may want to consider making your classes like this:

abstract class Base_Collection
{
    public int id = 0;
    public string title = "";

    public Base_Collection() { }

    public virtual void PerformAction() { } // or public virtual void PerformAction(){ }
}

class Book : Base_Collection
{
    public Book() { }

    public override void PerformAction() { // read book }
}

class Game : Base_Collection
{
    public Game() { }

    public override void PerformAction() { // play game }
}

class Movie : Base_Collection
{
    public Movie() { }

    public void PerformAction() { // watch movie }
}
Community
  • 1
  • 1
Ian R. O'Brien
  • 6,682
  • 9
  • 45
  • 73
  • What I truly try to achieve is have new methods for other derived classes that are only specific to them. Let's suppose I want to add a method called 'Bookmark()' in the Book class, the other derived classes like Game and Movie should have this method at all. – TheScholar Dec 09 '12 at 01:30
  • 1
    @TheScholar Then just add that method to the `Book` class - but as originally mentioned by @Will you won't be able to call that method directly from an instance of `Book` that is being passed as `Base_Collection`, you will either have to pass it as its derived type or cast it before calling the method. – slugster Dec 09 '12 at 01:47
  • You only have access to the members defined on that type. So for your base class, unless you cast it, you will only have access to the base class members. In order to use the methods on a derived class, you will need to cast your object as the same type as the derived object. – Ian R. O'Brien Dec 09 '12 at 01:52
2

Further to the answer from @Will (which is correct), you could structure your heirarchy a little better. For example, you do something different with each of the media types, but each type still gets consumed.

So change your base class to have an abstract base method called Consume(), which is then overridden and actually implemented in each derived class, this way you can pass around instances of your base class and there is no need for casting to invoke the Consume() method on each media type:

public abstract class Base_Collection
{

    public int id = 0;
    public string title = "";

    public Base_Collection() {   }

    public abstract void Consume();

}

public class Book : Base_Collection
{
    public Book() {   }

    public override void Consume()
    {
        //do book reading stuff in here
    }
}

public class Movie : Base_Collection
{
    public Movie() {   }

    public override void Consume()
    {
        //do movie watching stuff in here
    }
}



public class SomeOtherClass
{
    public void SomeMethod(Base_Collection mediaItem)
    {
        //note that the book/movie/whatever was passed as the base type
        mediaItem.Consume();
    }
}
slugster
  • 49,403
  • 14
  • 95
  • 145
1

Base_Collection doesn't have a method named Read_Book. To call the method on the derived class, you need to cast e.g.

(Book)book.Read_Book();
Will A
  • 24,780
  • 5
  • 50
  • 61
  • 1
    That won't fix the fact that the method cannot be override in the first place since it doesn't exist. – rae1 Dec 09 '12 at 00:28
1

You cannot override a method that doesn't exist. Remove the override and then cast before accesing the method, like Will mentions.

class Book : Base_Collection
{
    public Book()
    {

    }

    public void Read_Book()
    {

    }
}


public static void Main(string[] args)
{
    Base_Collection book = new Book();

    book.title = "The Dark Tower";
    (Book)book.Read_Book();
    ...
}

However, I would just create a Book object, rather than cast it, otherwise you'll have to do a lot of casting in your program. Maybe even rethink the class hierarchy, like slugster mentions.

rae1
  • 6,066
  • 4
  • 27
  • 48
  • Hey, I'm using your example but the compiler still doesn't want to accept it. EDIT: too bad, I can't show code while I comment. – TheScholar Dec 09 '12 at 01:20
  • using System; namespace polymorphism_test_01 { public abstract class Base_Collection { public int id = 0; public string title = ""; public Base_Collection() { } } public class Book : Base_Collection { public Book() { } public void Read_Book() { } } class Program { public static void Main(string[] args) { Base_Collection book = new Book(); book.title = "The Dark Tower"; (Book)book.Read_Book(); } } } – TheScholar Dec 09 '12 at 01:22
  • The errors are: "Error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement" and "'polymorphism_test_01.Base_Collection' does not contain a definition for 'Read_Book' and no extension method 'Read_Book' accepting a first argument of type 'polymorphism_test_01.Base_Collection' could be found (are you missing a using directive or an assembly reference?)" – TheScholar Dec 09 '12 at 01:24
  • okay, in your example you added the Read_Book method in Base_Collection, but actually I would prefer not to do that. Let's suppose I really need to add a method only specific for the Book derived class but other classes? – TheScholar Dec 09 '12 at 01:28
  • @TheScholar Actually no, I just removed the `override` keyword. ReadBook is only available to the Book class. However, you should really implement something like what the other answers mention, at least to avoid casting. – rae1 Dec 09 '12 at 01:28
0

You should either remove the override keyword from public override void Read_Book() or add this function to Base_Collection like below

    public abstract void Read_Book();
fatma.ekici
  • 2,787
  • 4
  • 28
  • 30