dcsimg
November 28, 2020
Hot Topics:

What is Shadowing, and Is It True that C++ Does It?

  • By Kate Gregory
  • Send Email »
  • More Articles »

A Simple Base Class

Let's start with some plain vanilla C++, no CLR in sight. Here's a base class:

class A
{
protected:
   int i;
   char* s;
public:
   A():s(NULL),i(-1) {}
   void f(int ii) {i=ii;s=new char(0);}
   void f(char* ss) {i=0; if (s) delete s; s=
        new char[strlen(ss)];strcpy(s,ss);}
   void report () { cout << i << " " << s << endl;}
};

While it isn't likely to win any contest for usefulness, and the second overload of f is a bit long for inlining, it will do. Clearly, you can use this class like this:

A a;
a.f(1);
a.report();
a.f("Hello");
a.report();

Deriving and Overloading

What happens to these overloads of f when I write a base class, B?

class B: public A
{
public:
    void nothing() {;}
    void f(int ii, char* ss){i=ii; if (s) delete s; s=
         new char[strlen(ss)];strcpy(s,ss);}
};

The answer, and this surprises many people, is that they seem to disappear. Here's some calling code:

B b;
b.nothing();
b.f(2);
b.report();
b.f("Yoo-Hoo!");
b.report();

This code compiles only when B::f(int, char*) is commented out. With that overload in place, this code produces messages such as 'B::f' : function does not take 1 arguments. You can call only the two-parameter version of f():

b.f(3,"Oops");
b.report();

Of course, if you absolutely need to get to the base class function, you can, but you have to be explicit about it:

b.A::f(4);
b.report();

Managed Classes

What happens if A and B become managed classes in a managed console application? (For simplicity, let's keep working with int and char*, but I will replace the iostream with System::Console equivalents.)

using namespace System;
__gc class A
{
protected:
   int i;
   char* s;
public:
   A():s(NULL),i(-1) {}
   void f(int ii) {i=ii;s=new char(0);}
   void f(char* ss) {i=0; if (s) delete s; s=
        new char[strlen(ss)];strcpy(s,ss);}
   void report () { Console::Write(__box(i));
                    Console::Write(" ");
                    Console::WriteLine(s);}
};

__gc class B: public A
{
public:
   void nothing() {;}
   void f(int ii, char* ss){i=ii; if (s) delete s; s=
        new char[strlen(ss)];strcpy(s,ss);}
};

Using these classes requires heap instances and -> instead of .:

   A* a = new A();
   a->f(1);
   a->report();
   a->f("Hello");
   a->report();
   B* b = new B();
   b->nothing();
   b->f(2);
   b->report();
   b->f("Yoo-Hoo!");
   b->report();
   b->f(3,"Oops");
   b->report();
   b->A::f(4);
   b->report();

This main won't compile, just as in the unmanaged case, because the two-parameter overload of f() hides the original one-parameter versions. If you comment out the offending lines, you get exactly the same results as in the unmanaged code.





Page 1 of 2



This article was originally published on February 27, 2004

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.


Thanks for your registration, follow us on our social networks to keep up-to-date