0

I am brand new to base classes so please correct me if I am wrong or I should be doing this another way, but I have coded a simple code snippet below that explains what I want to do.

class A : B
{
    private int _classId;

    public A (int id) : base(id)
    {
        _classId = id;
    }

    public string GetString()
    {
        return "This will eventually be an important string.";
    }
}

class B
{
    private int _classId;

    public B (int id)
    {
        // here I want to be able to get access to class A's methods
        // such as GetString() ...
    }

    public void SomeMethod()
    {

    }
}

So what I want to do is allow B to get A's methods.

Reason for doing this? I don't want to populate the class A because B is going to have a lot of methods so it would be cleaner to keep them in B then just get them from A in other code. Am I doing this wrong? is this not what base classes do? I simply just want to be able to still do this:

A.SomeMethodInB();

Without populating class A with junk and making it cleaner by storing it in class B

Ashkru
  • 1,495
  • 1
  • 17
  • 26
  • You should look at this reference for the protected keyword: https://msdn.microsoft.com/en-us/library/bcd5672a.aspx – Ehz Feb 24 '17 at 21:15
  • I think, you have missplaced base and derived classes, from your explaining, i understood, that you should make A class with a lot of protected methods base, and let b class derive from it – Maksim Simkin Feb 24 '17 at 21:18
  • 1
    _So what I want to do is allow B to get A's methods_. No -- it's the other way around. `A` gets the methods from `B`. If you want a method in `B` to call a method in `A`, declare the method `virtual` in `B` and `override` it in `A'. – David Culp Feb 24 '17 at 21:18

4 Answers4

1

Let me summarize your question:

  • You want a method that is only implemented in a descendant class (A)
  • You want this method to be available to both the base class (B) and the descendant class (A)
  • You want the base class to be able to call the descendant class' implementation of the method

This is the original definition of polymorphism (lately people have been using the term much more generally) and is bread-and-butter when it comes to OOP. It is also the hardest area of OOP to grasp for newcomers.

Write a base class with a virtual method

Let us start with the base class. Notice I have changed your example slightly, for a reason I will explain in a moment.

class B
{
    virtual protected string GetString()
    {
        return "I am a B";
    }

    public void DoSomethingWithGetString()
    {
        Console.WriteLine(GetString());
    }
}

In this example, DoSomethingWithGetString calls GetString. Note that GetString is virtual. This tells the compiler that we don't want to decide where the implementation of GetString is until runtime. This means it can't be bound at compile time: instead, its location is identified by a runtime Virtual Method Table that is set up when the object is created. If this code is running as part of a instance of class B, then it will call class B's implementation of GetString. But if this code was inherited, and is actually being called by some other object that descends from class B, it will call that class' version of GetString. This is called late binding.

Write the descendant class

So now let's write class A:

class A : B
{
    protected override GetString()
    {
        return "I am an A.";
    }
}

Because A descends from B, we don't need to implement anything else. If we call A.DoSomethingWithGetString it'll actually call B's implementation because it is inherited.

Execute it

If you run this code

var a = new A();
a.DoSomethingWithGetString();  //Output = "I am an A"

...the following will happen:

  1. An instance of A, which descends from B, is created
  2. The VMT of A is configured so that calls to GetString are sent to A.GetString.
  3. You call A.DoSomethingWithGetString
  4. This call is directed to B's code base, because A doesn't implement it.
  5. The code base in B detects that GetString is a virtual method, and calls it using the VMT.
  6. The VMT points to A's implementation of GetString.
  7. A.GetString is executed.

Thus you have an situation where code in class B is calling code in class A, which is what you asked for.

You can also run it this way:

B b = new A();
b.DoSomethingWithGetString(); //Output = "I am an A"

Thus you have a pointer to a B that says it's an A, because it is using a VMT set up for class A.

But I don't want any implementation in class B

Now, let's say you don't want class B to have any implementation at all for GetString, but you still want to be able to call the implementation in A. There is a way to do this using an abstract virtual method. Simply add the abstract keyword and remove the implementation:

abstract class B
{
    abstract protected string GetString(); //Notice no implementation

    public void DoSomethingWithGetString()
    {
        Console.WriteLine(GetString());
    }
}

Of course, now you can't use class B by itself, because it requires an implementation of GetString that will only be present in a descendant class. So you can no longer create an instance of B directly; you have to subtype, and use the subtype.

Can't use constructor

Now, you'll notice in my example I removed your constructor calls. There is a reason for this. A constructor should not ever call a method that is defined on a descendant class. The reason: during construction, constructors are called up and down the inheritance hierarchy, starting with the base class and moving down the descendant chain. That means, when you call B's constructor, A's constructor has not been called yet. if A's constructor hasn't run yet, we can't be sure that A has been properly set up yet, and therefore it is a really bad idea to call any of its methods.

There are some workarounds for this, but that is a topic for a different question.

Community
  • 1
  • 1
John Wu
  • 50,556
  • 8
  • 44
  • 80
0

If the method is only defined in Class A, then there is no way to access it through Class B.

If the method exists in both Class A and Class B, then you can use virtual method and override.

Wayne Cao
  • 35
  • 6
0

Think it is better to use the names BaseClass and DerivedClass in an example. The names A and B are kind of arbitrary. Although A comes before B, the names don't imply the direction of inheritance intended.

class Program
    {
        static void Main(string[] args)
        {
            var bc = new BaseClass(3);
            var dc = new DerivedClass(5);

            Console.WriteLine("Base Class Method A: " + bc.MethodA());
            Console.WriteLine("Derived Class Method A: " + dc.MethodA());
            Console.WriteLine("Base Class Method B: " + bc.MethodB());
            Console.WriteLine("Derived Class Method B: " + dc.MethodB());
            Console.ReadLine();
        }
    }

    public class BaseClass {
        protected int _classId;

        public BaseClass(int classId) {
            _classId = classId;
        }

        public virtual string MethodA() {
            return "Method A in base class: " + _classId.ToString();
        }

        public string MethodB()
        {
            return "I am a method B in the base class: " + _classId.ToString();
        }
    }

    public class DerivedClass : BaseClass {
        public DerivedClass(int classId)
            : base(classId)
        {

        }

        public override string MethodA() {
            return "Method A in derived class: " + _classId.ToString();
        }
    }
Ehz
  • 2,027
  • 1
  • 12
  • 11
0

There are two ways you can go about this. Let me first set out an example.

Here we have the base class that contains a method:

public class Base
{
    public void BaseMethod()
    {
        // Some method.
    }
}

Here is the derived class, where we want to call the method:

public class DerivedClass : BaseClass
{
    // We want to use BaseMethod() here.
}

In order to call a method from the base class, we use the base keyword.

public class DerivedClass : BaseClass
{
    base.BaseMethod();
}

This is fine if you want to just call the base method. However, if we want to change the method and define it with a different function, we have to declare it as virtual in the base class, as so:

public class Base
{
    public virtual void BaseMethod()
    {
        // Some method.
    }
}

In the derived class, we can now use the keyword override to override the virtual method of the base class, which redefines it to do something else:

public class DerivedClass : BaseClass
{
    public override void BaseMethod()
    {
        // Some new function.
    }
}
JMadelaine
  • 2,859
  • 1
  • 12
  • 17