September 1, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

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

  • February 27, 2004
  • 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



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel