Click here to Skip to main content
15,867,765 members
Articles / Programming Languages / C++/CLI
Article

Function overriding in C++/CLI

Rate me:
Please Sign up or sign in to vote.
4.81/5 (33 votes)
22 Jun 20045 min read 334.2K   37   25
Takes a look at new features like explicit overriding, renamed overriding, multiple overriding and sealing a method

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.

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

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

MC++
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

MC++
Base
handle referencing a Derived object.

MC++
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

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

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

IL for Derived::Boo

MSIL
.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

MSIL
.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

MSIL
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

MC++
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.

MC++
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 :-

MC++
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

MSIL
.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

MC++
virtual
method that's overriding a base class virtual method different from the one with the same name.

IL for Derived::Boo

MSIL
.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 :-

MC++
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 :-

MC++
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 :-

MC++
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

MSIL
.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.

MC++
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.

MC++
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 :-

MC++
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

MC++
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 :-)

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


Written By
United States United States
Nish Nishant is a technology enthusiast from Columbus, Ohio. He has over 20 years of software industry experience in various roles including Chief Technology Officer, Senior Solution Architect, Lead Software Architect, Principal Software Engineer, and Engineering/Architecture Team Leader. Nish is a 14-time recipient of the Microsoft Visual C++ MVP Award.

Nish authored C++/CLI in Action for Manning Publications in 2005, and co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his WordPress blog. Nish is experienced in technology leadership, solution architecture, software architecture, cloud development (AWS and Azure), REST services, software engineering best practices, CI/CD, mentoring, and directing all stages of software development.

Nish's Technology Blog : voidnish.wordpress.com

Comments and Discussions

 
GeneralC++ is doomed on Windows anyway ... Pin
Anonymous7-Jul-04 12:36
Anonymous7-Jul-04 12:36 
GeneralRe: C++ is doomed on Windows anyway ... PinPopular
Giancarlo Aguilera30-Mar-05 7:26
Giancarlo Aguilera30-Mar-05 7:26 
JokeRe: C++ is doomed on Windows anyway ... Pin
doublej8-Mar-10 10:36
doublej8-Mar-10 10:36 
GeneralRe: C++ is doomed on Windows anyway ... Pin
Kiriander7-Feb-22 4:16
Kiriander7-Feb-22 4:16 
QuestionHas Microsoft said anything about the purpose of these features? Pin
Don Clugston28-Jun-04 21:25
Don Clugston28-Jun-04 21:25 
AnswerRe: Has Microsoft said anything about the purpose of these features? Pin
Nish Nishant30-Jun-04 16:09
sitebuilderNish Nishant30-Jun-04 16:09 
GeneralRe: Has Microsoft said anything about the purpose of these features? Pin
Don Clugston30-Jun-04 17:23
Don Clugston30-Jun-04 17:23 
GeneralMSDN Webcast: The New C++: Overriding, Templates, and Generics &#8211; June 30th Pin
Kant28-Jun-04 11:52
Kant28-Jun-04 11:52 
GeneralRe: MSDN Webcast: The New C++: Overriding, Templates, and Generics &#8211; June 30th Pin
Nish Nishant28-Jun-04 15:09
sitebuilderNish Nishant28-Jun-04 15:09 
QuestionDid they ever proposed changes in the C++ standard ? Pin
Bamaco223-Jun-04 11:48
Bamaco223-Jun-04 11:48 
AnswerRe: Did they ever proposed changes in the C++ standard ? Pin
Nish Nishant23-Jun-04 16:25
sitebuilderNish Nishant23-Jun-04 16:25 
AnswerRe: Did they ever proposed changes in the C++ standard ? Pin
mlkeS29-Jun-04 14:26
mlkeS29-Jun-04 14:26 
AnswerRe: Did they ever proposed changes in the C++ standard ? Pin
Anonymous3-Jul-04 12:42
Anonymous3-Jul-04 12:42 
GeneralOh boy. Pin
Chris Maunder23-Jun-04 8:06
cofounderChris Maunder23-Jun-04 8:06 
GeneralRe: Oh boy. Pin
Jörgen Sigvardsson26-Jun-04 5:53
Jörgen Sigvardsson26-Jun-04 5:53 
GeneralI'm Impressed Pin
Kannan Kalyanaraman23-Jun-04 7:28
Kannan Kalyanaraman23-Jun-04 7:28 
GeneralRe: I'm Impressed Pin
Nish Nishant23-Jun-04 16:22
sitebuilderNish Nishant23-Jun-04 16:22 
GeneralNice... Pin
Nemanja Trifunovic23-Jun-04 2:57
Nemanja Trifunovic23-Jun-04 2:57 
GeneralRe: Nice... Pin
Nish Nishant23-Jun-04 3:04
sitebuilderNish Nishant23-Jun-04 3:04 
GeneralRe: Nice... Pin
Kevin McFarlane23-Jun-04 4:26
Kevin McFarlane23-Jun-04 4:26 
GeneralRe: Nice... Pin
Peter Gummer5-Dec-04 0:18
Peter Gummer5-Dec-04 0:18 
GeneralNice Overview... Pin
HumanOsc23-Jun-04 2:36
HumanOsc23-Jun-04 2:36 
GeneralRe: Nice Overview... Pin
Nish Nishant23-Jun-04 2:57
sitebuilderNish Nishant23-Jun-04 2:57 
HumanOsc wrote:
But i think when i use this new Compiler i must rewritten my old managed c++ sources... (???)

The old syntax will continue to be supported in Whidbey and perhaps Orcas too, but it is most advisable that you port all your code to the new syntax.

You can use some kind of "old syntax to new syntax" convertor tools that should hopefully be ready by next year Smile | :)


My take on gmail - Is gmail just a fashion statement?
My blog on C++/CLI, MFC/Win32, .NET - void Nish(char* szBlog);
My MVP tips, tricks and essays web site - www.voidnish.com

GeneralRe: Nice Overview... Pin
HumanOsc23-Jun-04 19:59
HumanOsc23-Jun-04 19:59 
GeneralRe: Nice Overview... Pin
Kevin McFarlane23-Jun-04 4:29
Kevin McFarlane23-Jun-04 4:29 

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

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