Click here to Skip to main content
Click here to Skip to main content

Function overriding in C++/CLI

By , 22 Jun 2004
Rate this:
Please Sign up or sign in to vote.

Introduction

This article will demonstrate some of the new features provided by C++/CLI in connection with function overloading. Since, at the time of writing this article, the author only has access to an alpha version of the compiler, some of the code snippet syntax shown here might change in the final release, which is expected to be post-June 2005. Of course, the article will be updated whenever the author gets a newer version of the compiler where the syntax is slightly different from how it's portrayed in this article. Readers are expected to know basic C++/CLI syntax, and if they don't, the author strongly recommends that they take a look at one of the author's own articles - A first look at C++/CLI; which gives a basic introduction to the new C++/CLI syntax introduced by Microsoft, starting with VC++ Whidbey.

Explicit overriding

In native C++, a derived class function having the same name and parameters as a base class virtual function will *always* override it. In C++/CLI you have the option of using the new contextual keyword to specify whether you want to override a base class function or hide it.

BTW I have used the following #define as I didn't want to type in (or even copy/paste) Console::WriteLine all the time.

#define Show(x) Console::WriteLine(x)

The following code snippet demonstrates the use of the new contextual keyword.

ref class Base
{
public:
    virtual void Goo()
    {
        Show("Base::Goo");
    }
    
    virtual void Boo()
    {
        Show("Base::Boo");
    }
    
    virtual void Doo()
    {
        Show("Base::Doo");
    }
};

ref class Derived : Base
{
public:
    //Overrides Base::Goo
    virtual void Goo()
    {
        Show("Derived::Goo");
    }
    
    //Overrides Base::Boo as above
    virtual void Boo() = Base::Boo
    {
        Show("Derived::Boo");
    }
    
    //Hides Base::Doo
    virtual void Doo() new
    {
        Show("Derived::Doo");
    }
};

Here's some sample code that invokes the above methods on a Base handle referencing a Derived object.

void _tmain()
{
    Base^ r = gcnew Derived();
    r->Goo();
    r->Boo();
    r->Doo();
}

You'll get the following output :-

Derived::Goo
Derived::Boo
Base::Doo

Let's look at part of the IL generated for each of these methods :-

IL for Derived::Goo

.method public virtual instance void  Goo() cil managed
{
  .maxstack  1
  //...
  IL_000a:  ret
}

Okay, nothing peculiar about that code, everything seems normal Smile | :)

IL for Derived::Boo

.method public newslot virtual final instance void 
        Boo() cil managed
{
  .override Base::Boo
  .maxstack  1
  //...
  IL_000a:  ret
}

Hmmm, notice the .override IL directive that has been generated, which specifies that a new virtual method should be generated using the same signature as in the base class, but with a different name, and it's this name that is specified by the .override directive. Of course, it does not really affect the result in our above case because it again simply mentions the base class's method-name which is same as the derived class's method-name. Later, when we look at renamed overriding, we'll see a more appropriate use of the .override directive.

IL for Derived::Doo

.method public newslot virtual instance void 
        Doo() cil managed
{
  .maxstack  1
   //...
  IL_000a:  ret
}

Notice the newslot IL keyword that has been used in the method definition. If any method definition is marked as newslot then it always creates a new virtual method, even if its base class defines a virtual method with the same name and parameter list.

Renamed overriding

Native C++ insisted that the derived class method name must match the name of the base class virtual method that it is overriding. C++/CLI allows us to have a derived class method override a base class virtual method even if the derived class method name does not match the base class method name. Of course the method signatures must be equivalent. The following code snippet should make things clear.

ref class Base
{
public:
    virtual void Goo()
    {
        Show("Base::Goo");
    }

    virtual void Boo()
    {
        Show("Base::Boo");
    }    
};

ref class Derived : Base
{
public:
    //Overrides Base::Goo
    virtual void Goo()
    {
        Show("Derived::Goo");
    }

    //Overrides Base::Boo
    virtual void Woo() = Base::Boo
    {
        Show("Derived::Woo");
    }

    //New function Boo in Derived
    virtual void Boo() new
    {
        Show("Derived::Boo");
    }
};

Some code that invokes these methods :-

void _tmain()
{
    Base^ r = gcnew Derived();
    r->Goo();
    r->Boo();    
    
    Derived^ d = dynamic_cast<Derived^>(r);
    d->Goo();
    d->Boo();
    d->Woo();
}

The output will be :-

Derived::Goo
Derived::Woo
Derived::Goo
Derived::Boo
Derived::Woo

Let's look at the IL for Derived::Woo and Derived::Boo.

IL for Derived::Woo

.method public newslot virtual final instance void 
        Woo() cil managed
{
  .override Base::Boo
  .maxstack  1
   //...
 IL_000a:  ret
}

As mentioned earlier, the IL .override directive allows us to have a derived class method generated, that will override a base class virtual method of a different name but the same signature. You'll also notice that the newslot keyword has been added to the method definition so that a new virtual method will be generated. In this way, even if the base class had a method of the same name, the derived class method will actually be a new virtual method that's overriding a base class virtual method different from the one with the same name.

IL for Derived::Boo

.method public newslot virtual instance void 
        Boo() cil managed
{
  .maxstack  1
  //...
  IL_000a:  ret
} // end of method Derived::Boo

If we hadn't specified Derived::Boo as a new method, we'd have got a compiler error, as Base::Boo has been overridden by Derived::Woo :-

error C3663: 'Derived::Boo' : 
   method implicitly overrides 'Base::Boo' 
   which has already been explicitly overridden

But since we have specified that this function is a new virtual function, the generated IL uses the IL newslot keyword on the method definition.

Alternative syntax

A slightly cleaner looking syntactic alternative is to use the contextual identifier override as shown below :-

ref class Derived : Base
{
public:
    //...

    //Override Base::Boo
    virtual void Woo() override = Base::Boo
    {
        Show("Derived::Woo");
    }

    //...
};

Multiple overriding

In native C++, a function of a class that inherits from multiple base classes/interfaces, can override more than one base class function only if all the base classes/interfaces have a function of the same name and signature. C++/CLI lets you specify which method overrides which base/ class/interface method, provided the function signatures match.

The following code snippet demonstrates multiple overriding :-

interface class INish
{
    void Goo();
};

interface class IBuster
{
    void Boo();
    void Moo();
};

ref class Base
{
public:
    virtual void Goo() 
    {
        Show("Base::Goo");
    }

    virtual void Boo()
    {
        Show("Base::Boo");
    }    
};

ref class Derived : Base, INish, IBuster
{
public:    
    //Overrides both Base::Goo, INish::Goo, IBuster::Moo
    virtual void Goo() = Base::Goo, INish::Goo, IBuster::Moo
    {
        Show("Derived::Goo");
    }

    //Overrides Base::Boo
    virtual void Boo() = Base::Boo
    {
        Show("Derived::Boo");
    }

    //Override IBuster::Boo
    virtual void Hoo()= IBuster::Boo
    {
        Show("Derived::Hoo");
    }    
};

Use the below code snippet to invoke these methods :-

void _tmain()
{
    Base^ r = gcnew Derived();
    r->Goo();
    r->Boo();    

    INish^ i = dynamic_cast<INish^>(r);
    i->Goo();
    

    IBuster^ b = dynamic_cast<IBuster^>(r);
    b->Boo();
    b->Moo();
}

The output will be :-

Derived::Goo
Derived::Boo
Derived::Goo
Derived::Hoo
Derived::Goo

Let's see how the generated IL looks like.

IL for Derived::Goo

.method public newslot virtual final instance void 
        Goo() cil managed
{
  .override IBuster::Moo
  .override INish::Goo
  .override Base::Goo
  .maxstack  1
  //... 
  IL_000a:  ret
}

Alright, that's not a biggie, is it? All that happens is that the .override IL directive is used multiple times, each time specifying a different base class or interface.

Sealing a function from further overriding

Sometimes we might desire that a function should not be overridden somewhere down the inheritance chain. That's where the sealed function modifier comes handy.

ref class Base
{
public:
    virtual void Goo() sealed
    {
        Show("Base::Goo");
    }
};

ref class Derived : Base
{
public:    
    virtual void Goo() //won't compile
    {
        Show("Derived::Goo");
    }    
};

The compiler will throw up an error :-

error C3248: 
  'Base::Goo': function declared as 'sealed' 
   cannot be overridden by 'Derived::Goo'

Of course you can get it to compile by using the new function-modifier.

ref class Base
{
public:
    virtual void Goo() sealed
    {
        Show("Base::Goo");
    }
};

ref class Derived : Base
{
public:    
    virtual void Goo() new
    {
        Show("Derived::Goo");
    }    
};

But if you do this, then the following code snippet :-

void _tmain()
{
    Base^ r = gcnew Derived();
    r->Goo();    
}

...will give the following output :-

Base::Goo

...because Derived::Goo is now a new function and the generated IL will have the newslot keyword applied to the method definition.

The abstract function-modifier

ref class Base
{
public:
    virtual void Goo() abstract;
    virtual void Boo()
    {
        Show("Base::Boo");
    }
};

The line virtual void Goo() abstract; is syntactically equivalent to virtual void Goo() = 0; and the abstract function-modifier exists only to provide an uniform syntactical style.

Conclusion

As mentioned in the introduction, this article is based on my experiences with the latest version of the alpha compiler I could lay my hands on. Some of the syntax demonstrated in the article might change by the time VC++.NET Whidbey is finally released. But however that might turn out to be, I must say I am quite fairly impressed by the awesome changes that the VC++ team is bringing to the compiler. Thanks guys Smile | :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Nish Sivakumar

United States United States
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

Comments and Discussions

 
GeneralC++ is doomed on Windows anyway ... PinsussAnonymous7-Jul-04 12:36 
GeneralRe: C++ is doomed on Windows anyway ... PinmemberGiancarlo Aguilera30-Mar-05 7:26 
JokeRe: C++ is doomed on Windows anyway ... Pinmemberdoublej8-Mar-10 10:36 
QuestionHas Microsoft said anything about the purpose of these features? PinmemberDon Clugston28-Jun-04 21:25 
AnswerRe: Has Microsoft said anything about the purpose of these features? PinstaffNishant S30-Jun-04 16:09 
GeneralRe: Has Microsoft said anything about the purpose of these features? PinmemberDon Clugston30-Jun-04 17:23 
GeneralMSDN Webcast: The New C++: Overriding, Templates, and Generics &#8211; June 30th PinmemberKant28-Jun-04 11:52 
GeneralRe: MSDN Webcast: The New C++: Overriding, Templates, and Generics &#8211; June 30th PinstaffNishant S28-Jun-04 15:09 
QuestionDid they ever proposed changes in the C++ standard ? PinmemberBamaco223-Jun-04 11:48 
AnswerRe: Did they ever proposed changes in the C++ standard ? PinstaffNishant S23-Jun-04 16:25 
AnswerRe: Did they ever proposed changes in the C++ standard ? PinmembermlkeS29-Jun-04 14:26 
AnswerRe: Did they ever proposed changes in the C++ standard ? PinsussAnonymous3-Jul-04 12:42 
GeneralOh boy. PinadminChris Maunder23-Jun-04 8:06 
GeneralRe: Oh boy. PinmemberJörgen Sigvardsson26-Jun-04 5:53 
GeneralI'm Impressed PinmemberKannan Kalyanaraman23-Jun-04 7:28 
GeneralRe: I'm Impressed PinstaffNishant S23-Jun-04 16:22 
GeneralNice... PinmemberNemanja Trifunovic23-Jun-04 2:57 
GeneralRe: Nice... PinstaffNishant S23-Jun-04 3:04 
GeneralRe: Nice... PinmemberKevin McFarlane23-Jun-04 4:26 
GeneralRe: Nice... PinmemberPeter Gummer5-Dec-04 0:18 
GeneralNice Overview... PinmemberHumanOsc23-Jun-04 2:36 
GeneralRe: Nice Overview... PinstaffNishant S23-Jun-04 2:57 
GeneralRe: Nice Overview... PinmemberHumanOsc23-Jun-04 19:59 
GeneralRe: Nice Overview... PinmemberKevin McFarlane23-Jun-04 4:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 23 Jun 2004
Article Copyright 2004 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid