Click here to Skip to main content
15,886,258 members
Articles / Programming Languages / C++

Extension of 'virtual' keyword to Add More Semantic

Rate me:
Please Sign up or sign in to vote.
3.30/5 (7 votes)
9 Sep 2014CPOL7 min read 23.7K   3   30
Discusses possible improve of C++ around the 'virtual' keyword.

Introduction

You can add only few lines of code into your top header to be able to write C++ classes with better semantic.

C++
/*
virtual - standard modifier for all cases.

virtnew - class adds a new virtual method.
virtovr - overriden virtual method, when it not fits to below cases (rare?):

virtabs - abstract virtual method. In ideal do not requires =0. But still allows it.
virtimp - the first implementation of an abstract method from the parent class. 

virtrep - REPLACEs the parent alg. Cannot have call to it.
virtadd - ADDs something AFTER the parent alg. 
virtins - INSERTs something before the parent alg. 
virtwrp - WRAPs the parent alg before and after.
*/

#define virtovr virtual
#define virtnew virtual
//
#define virtabs virtual
#define virtimp virtual
//
#define virtrep virtual
#define virtadd virtual
#define virtins virtual
#define virtwrp virtual 

Consider this as suggestion to improve C++ language. Such extention will not force developers to use it, but if somebody want he can start use it. Without compiler support we still can use this in our code, but there is no error messages.

Background

C++11 override

Many years we have live with 'virtual' keyword in C++ until its improvement in C++11 with additional 'override' specifier. This was the first push to think about the subject.

I never liked the idea to put this speciifer at the end of function declaration, because if you have functions with parameters it becomes more and more hidden. Eye of developer should jump more over the code to find and recognize it.

C++
virtual void foo() const override; 

virtual void SomeGoodName(
                const char*     inParam1,
                long long int   inParam2,
                std::vector     inParam3 ) const override;

I would prefer to have this information first in the line:

C++
virtovr void foo() const; 

virtovr void SomeGoodName(
                const char*     inParam1,
                long long int   inParam2,
                std::vector     inParam3 ) const;

virtovr - is combination of 'virtual override'.

I have notice that virtual, inline, static keywords, which can go before a function declaration, have length 6-7 chars. This is why all new "keywords" have the same length.

As for me, such keyword is more readable, short and consistent in the text of C++ code, comparing to 'override' at the end of function declaration.
 

Next idea - virtnew

In our projects we have C++ classes that not only override a parent virtual method, but add more.

If to think about what happens on the low level, then it is easy to see that such virtual method allocates a new position in the virtual table of the C++ class.

C++
class A
{
virtual ~A();
virtual void f1();
virtual void f2();
};

class B : public A
{
virtual ~B();
virtovr void f1();
virtovr void f2();

virtual void f3();
};
  • Virtual table of class A contains 3 items - pointers to class methods.
  • Virtual table of class B contains 4 items. Virtual method f3() introduced in this class needs one more.

We can consider this as fundamental difference between overriden virtual methods f1, f2 and ... a new virtual method f3.

This bring us to idea of 'virtnew' keyword.

class B : public A
{
virtual ~B();

virtovr void f1();
virtovr void f2();

virtnew void f3();
};

Advantages:

* Developer _reading_ 'virtnew' immediately understands that the parent class do NOT contain this method.
* Compiller and smart IDE can check this fact providing error messages similar to 'override' in C++11.

Yes of course, without support of this by compiller, it looks to be a very weak idea. But during last couple of years, me personally have used this in the most complex classes of our project, and I have found this to be helpful.
 

virtins, virtadd, virtwrp, virtrep

As I have said, we was using this virtnew and virtovr keywords last few years. Few months ago, I have recall some article with some critic of C++ features. One of that was: developer cannot specify how a virtual method can be implemented in a child class:

  • call parent method at first and add some code: { inherited::foo(); code_after; }
  • some code and call parent method at the end: { code_before; inherited::foo(); }
  • call of parent method is wrapped by some code: { code_before; inherited::foo(); code_after; }
  • replace parent method { alternative_code }

This have force me to look on existed code under a new point of view. So we have at least 4 different cases/patterns of a child OVERRIDEN virtual method. Then why we should to use the same keyword 'virtovr' for them all? May be there is sense to have more keywords?

class C : public B
{
virtual ~C();

virtrep void f1();
virtadd void f2();
virtins void f3();
virtwrp void f4();
};

What advantage of this?

* Developer reads virtrep - 'virtual replace', and understands that class C overrides f1() from a parent clas. Becides, method is implemented as REPLACEMENT to parent algorithm. Developer understands that if go to C::f1() he will not see there call to B::f1().

IMPORTANT: developer understands this reading only ONE word of the text.

* virtadd - 'virtual adds' - overriden method at first do calls the parent method later do more code.

* virtins - 'virtual insert' - overriden method at first do some new own code, later do calls the parent method.

* virtwrp - 'virtual wrap' - overriden method do calls the parent method, but wrapps it before and after with some additional code.

* virtrep - 'virtual replace' - overriden method do not calls the parent method, but provides alternative algorithm.
 

OBSERVATION:

  • Both "virtual ... override" and "virtovr" expose the fact that method is overriden.
  • virtins, virtadd, virtwrp, virtrep - additionally expose how it was overriden.

Smart IDE, in ideal, should monitor the code of functions to recognise a pattern of code, and prompt to developer or even automatically correct class declaration.
 

virtimp

Later in discussion with developers, one of them have recognized one more case/pattern of overriden virtual method - this is the first implementation of abstract parent method.

C++
class A
{
virtnew void foo() = 0;
};


class B : public class A
{
virtimp void foo();
};

Keyword 'virtimp' says us that this is a overriden virtual method of a parent class, which was abstract in the parent class, and this is its first implemenation in the hierarchy chain.

Compiller/IDE can check this fact to provide error messages.

virtabs

Finally, 'virtabs' keywrod - 'virtual abstract', can be replacement of =0 syntax. But for compatibility still allows it. All examples below are valid. Notice that an abstract method is always a virtnew method at least.

C++
class A
{
virtnew void foo() = 0;  // virtnew underlines that this is new method in game, 
                         // =0 says it is abstract.

virtabs void foo();      // the most prefered new style. But requires compiler support.  
virtabs void foo() = 0;  // for compatibility
};

 

Destructors

Desctructors do not call directly parent destructors. So virtadd, virtins, virtwrp will not have sense for them.

We can use may be only virtovr or virtrep keywords for destructors. But taking into account that destructor are called one by one, we cannot say that they replace each other.

This brings us to point that we should use virtovr only.

C++
class A
{
virtnew ~A();
};

class B : public A
{
virtovr ~B();
}

Examples

This is a real life example of one of our classes as is:

C++
class ValueSorter_Indirect : public ValueSorter_InPlace
{
        typedef ValueSorter_InPlace inherited;

    public://///////////////////////////////////////////////////////////////////////////////////

                            ValueSorter_Indirect(
                                I_Index_Ptr   inIndex,
                                uint64_t      inRamToUse,
                                bool          inSwapBytes );
                            
virtovr                     ~ValueSorter_Indirect( void );

             
    public://///////////////////////////////////////////////////////////////////////////////////

// I_ValueSorter API:

virtadd void                Init( void );
virtrep void                FinalFlushToIndex( void );
  

    protected://////////////////////////////////////////////////////////////////////////////////

// ValueSorter_InPlace:
                  
        // Value Methods:

virtins void                AddImp(
                                I_Value_Ptr   inValue,
                                REC_ID        inRecID );

        // Buffer Methods:

virtrep uint32_t            CalcBuffSize( void ) const;
virtrep uint32_t            CalcMaxPairs( void ) const;

virtrep void                Sort( void ) const;


   protected://////////////////////////////////////////////////////////////////////////////////

// THIS CLASS:

                            // These methods can be overridden in child-class(es) 
                            // to change work with mPointers array.  They are called by Sort().
virtnew void                ArrayOfPointers_Prepare( void );
virtnew void                ArrayOfPointers_Cleanup( void );


   protected://////////////////////////////////////////////////////////////////////////////////

        char**              mPointers;        // array of pointers to mPairs.
};

Lets analyse this code with the case when we have just 'virtual' and 'override'.

1) virtadd. Compare this line

C++
virtadd void                Init( void );

vs

C++
virtual void                Init( void ) override; 

In both cases we understand that method Init()

  • is virtual AND
  • it presents in the parent class AND
  • we override it here to change something.

You cannot get more information from the second line.
Once again. You cannot get more information because it not exists there.

But the first line gives me additionally:

  • understanding how looks algorithm in .cpp file. It looks as { inherited::Init(); more_code; }

WOW! 3 magic chars virtADD allow to my brain to see picture of algorithm in OTHER file.
WOW! 3 magic chars virtADD allow to my brain to see DEPENDENCY to a parent class method.

Besides! The first line allows to me:

  • less to type and less to read by eye. GOOD.

We have win-win solution! Isn't this a direction for C++11? Do more with less code.

2) virtrep. Few methods marked as 'virtual + replace = virtrep'. We understand that such method:

  • totally REPLACEs the parent's algorithm.
  • it not calls the parent algorightm.

3) virtnew. Two methods are marked as 'virtual + new'. So I understand right here, that

  • parent class do not have such methods, they are introduced in the current class.
  • Some method(s) of this class must call them to use polimorphism of this methods. In the example Sort() method calls ArrayOfPointers_Prepare() and ArrayOfPointers_Cleanup().
  • Some child-class can and, most probably, will override these virtnew methods, otherwise no sense to make them virtual.

Compare to C#

While I have write this article, I have note another one: Popular Misconception: The override that was not, where I have to see syntax for C#. They put override keyword at the start of function declaration.

C#
class Derived : MyBase
{
    public override string MethodA()
    {
        return "Hello from Derived::MethodA";
    }
    public new string MethodB()
    {
        return "Hello from Derived::MethodB";
    }
}

In C++ language the 'override' was made as a specifier of function, similar to 'const', which by parser rules go at the end of function declaration.

But this is not a dogma. Developers of C++ parser can implement rules to have it as in C# if will be such wish.

Also note that C# allows new keyword. This sounds similar to 'virtnew'.

Final

Once again, yes it is clear that without compiller and IDE support it is easy to get "out-of date" keywords in the class declaration, which not correspond to the algorithm of virtual method.

Here we only expose idea ...

In the same time we try to use it in our many-years projects. This really saves time of understanding when developer reads code.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Paradigma Software, Inc.
Ukraine Ukraine
Ruslan Zasukhin is original developer of Valentina Database yet from 1993. He is co-founder of Paradigma Software, Inc. USA based company, which develops Valentina product line, including Valentina DB & Report Server, Valentina DB & Report ADK, Valentina Studio. http://www.valentina-db.com

Comments and Discussions

 
QuestionNot that useful, some keywords are implementation dependend Pin
Stefan_Lang15-Sep-14 4:10
Stefan_Lang15-Sep-14 4:10 
AnswerRe: Not that useful, some keywords are implementation dependend Pin
Ruslan Zasukhin15-Sep-14 7:09
Ruslan Zasukhin15-Sep-14 7:09 
AnswerRe: Not that useful, some keywords are implementation dependend Pin
Ruslan Zasukhin15-Sep-14 7:47
Ruslan Zasukhin15-Sep-14 7:47 
GeneralRe: Not that useful, some keywords are implementation dependend Pin
Stefan_Lang16-Sep-14 0:14
Stefan_Lang16-Sep-14 0:14 
GeneralRe: Not that useful, some keywords are implementation dependend Pin
Ruslan Zasukhin16-Jul-15 10:34
Ruslan Zasukhin16-Jul-15 10:34 
GeneralRe: Not that useful, some keywords are implementation dependend Pin
Stefan_Lang16-Jul-15 20:21
Stefan_Lang16-Jul-15 20:21 
QuestionIt looks like a custom solution to design problems in your 20 year old project. Pin
john morrison leon14-Sep-14 23:19
john morrison leon14-Sep-14 23:19 
AnswerRe: It looks like a custom solution to design problems in your 20 year old project. Pin
Ruslan Zasukhin15-Sep-14 0:36
Ruslan Zasukhin15-Sep-14 0:36 
QuestionInformation hiding broken Pin
Andreas Gieriet14-Sep-14 1:49
professionalAndreas Gieriet14-Sep-14 1:49 
AnswerRe: Information hiding broken Pin
Ruslan Zasukhin14-Sep-14 3:29
Ruslan Zasukhin14-Sep-14 3:29 
GeneralRe: Information hiding broken Pin
Andreas Gieriet14-Sep-14 3:56
professionalAndreas Gieriet14-Sep-14 3:56 
GeneralRe: Information hiding broken Pin
Ruslan Zasukhin14-Sep-14 4:14
Ruslan Zasukhin14-Sep-14 4:14 
GeneralRe: Information hiding broken Pin
Ruslan Zasukhin14-Sep-14 4:24
Ruslan Zasukhin14-Sep-14 4:24 
GeneralRe: Information hiding broken Pin
Andreas Gieriet14-Sep-14 5:10
professionalAndreas Gieriet14-Sep-14 5:10 
GeneralRe: Information hiding broken Pin
Ruslan Zasukhin14-Sep-14 9:41
Ruslan Zasukhin14-Sep-14 9:41 
AnswerRe: Information hiding broken Pin
Ruslan Zasukhin14-Sep-14 4:11
Ruslan Zasukhin14-Sep-14 4:11 
GeneralRe: Information hiding broken Pin
Andreas Gieriet14-Sep-14 5:02
professionalAndreas Gieriet14-Sep-14 5:02 
GeneralRe: Information hiding broken Pin
Ruslan Zasukhin14-Sep-14 9:03
Ruslan Zasukhin14-Sep-14 9:03 
GeneralRe: Information hiding broken Pin
Ruslan Zasukhin14-Sep-14 9:36
Ruslan Zasukhin14-Sep-14 9:36 
GeneralRe: Information hiding broken Pin
Andreas Gieriet14-Sep-14 10:55
professionalAndreas Gieriet14-Sep-14 10:55 
GeneralTry the ISO committee Pin
WillemSe9-Sep-14 23:57
WillemSe9-Sep-14 23:57 
GeneralRe: Try the ISO committee Pin
Ruslan Zasukhin11-Sep-14 1:37
Ruslan Zasukhin11-Sep-14 1:37 
QuestionI don't think that language standards and compiler writers are going to bow to this. Pin
john morrison leon9-Sep-14 15:12
john morrison leon9-Sep-14 15:12 
You aren't really offering very much other than a bunch of keywords that all have the same effect as an existing one. If you mask a keyword like that you only make it difficult for programmers to understand the language. I don't think that language standards and compiler writers are going to bow to this.

If you really believe in this idea then find a way to enforce it using compile time template techniques. That way you can get it working yourself. It will have a template syntax but that will help other programmers to better understand the kind of change you are making to the familiar language.

I'm not going to vote you down, or up. The leading vote of 1 is more than cruel enough.
AnswerRe: I don't think that language standards and compiler writers are going to bow to this. Pin
Ruslan Zasukhin9-Sep-14 22:57
Ruslan Zasukhin9-Sep-14 22:57 
GeneralRe: I don't think that language standards and compiler writers are going to bow to this. Pin
john morrison leon9-Sep-14 23:10
john morrison leon9-Sep-14 23:10 

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.