Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #19051

Re: Non virtual and inheritance

From Rui Maciel <rui.maciel@gmail.com>
Newsgroups comp.lang.c++
Subject Re: Non virtual and inheritance
Date 2012-10-18 14:49 +0100
Organization Aioe.org NNTP Server
Message-ID <k5p1di$evk$1@speranza.aioe.org> (permalink)
References <k5oqnl$slk$1@speranza.aioe.org>

Show all headers | View raw


Sensei wrote:

> I was philosophizing on inheritance in C++, and I was wondering this.
> Bear with me, as this is something more of a philosophy/history, rather
> than a technical one.
> 
> What would be a use case for non virtual members in a class hierarchy?
> 
> 
>      class Base
>      {
>      public:
>          virtual void hello() { std::cout << "Base" << std::endl; }:
>      }
> 
>      class Derived : public Base
>      {
>      public:
>          virtual void hello() { std::cout << "Derived" << std::endl; }:
>      }
> 
> 
> Virtual allows me to use a Base class, and yet call the right function
> hello().
> 
> 
>      Base *b = new Base;
>      Base *d = new Derived;
>      b->hello();
>      d->hello();
> 
> 
> Now, if I let virtual out from Base and Derived, I will "slice" the
> derived class, and d->hello() will print, "Base".
> 
> Why is a member function non-virtual by default, even from an
> historically accurate point of view?

See the answer provided by Nobody.


>  From a user point of view, the "slicing" is an "error", or an
> unexpected behavior, to say the least. Having a base class pointer is
> useful, and it will call the right derived class when needed.

No.  It may go against your perception of how virtual functions work, but it 
is far from an error.  If you define void Base::hello() and when you call 
the member function hello() of an object of type Base , you cannot be 
surprized if, by doing so, you end up calling void Base::hello().  The 
program is running exactly as you set it to run.


> Not only that, but choosing non-virtual as the default behavior, means
> that virtual is quite "extravagant", and therefore needs to be added by
> hand. But, at least in my experience, virtual is a given, and
> non-virtual is the exception.

Then declare the member functions of your base class as virtual.  If you 
declare a virtual member function in a base class then whenever you define 
the same member function in a derived class, that member function will be 
virtual whether you explicitly define it as virtual or not.


> I'd really like to understand the rationale behind this choice, with a
> use case that makes sense from an operational point of view, and not
> just as an academic exercise.

<source lang="cpp">
#include <iostream>


struct Base
{
        void foo() { } 
};

struct DerivedA: public Base
{
        virtual void foo() { } 
};

struct DerivedB: public Base
{
        void foo() { } 
};



int main(void)
{
        using namespace std;
        cout << "Base size: " << sizeof(Base) << "\n";
        cout << "DerivedA size: " << sizeof(DerivedA) << "\n";
        cout << "DerivedB size: " << sizeof(DerivedB) << endl;
        return 0;
}
</source>

<shell>
rui@kubuntu:tmp$ g++ main.c++ 
rui@kubuntu:tmp$ ./a.out 
Base size: 1
DerivedA size: 8
DerivedB size: 1
</shell>


> This question bugged me when I tried to make only Derived non-virtual,
> and subclassing it.
> 
> 
>      class Base
>      {
>      public:
>          virtual void hello() { std::cout << "Base" << std::endl; };
>      };
> 
>      class Derived : public Base
>      {
>      public:
>          void hello() { std::cout << "Derived" << std::endl; };
>      };
> 
>      class Last : public Derived
>      {
>      public:
>          void hello() { std::cout << "Last" << std::endl; };
>      };
> 
> 
> At least on my system (Apple clang version 4.1 x86_64-apple-darwin12.2.0
> Thread model: posix), it seems that "virtual" survives:
> 
> 
>      Base *b = new Base;
>      Base *d = new Derived;
>      Base *l = new Last;
>      b->hello();
>      d->hello();
>      l->hello();
> 
> % clang++ a.cpp  && ./a.out
> clang++ a.cpp  && ./a.out
> Base
> Derived
> Last
> 
> 
> Is this the correct behavior? Why is this?

Yes.  You've declared Base::hello() as virtual.  Hence, every* time you 
declare that member function in a class that directly or indirectly derives 
from Base, the member function defined in the derived class will also be 
virtual.


Rui Maciel


* The "every time" bit may not be entirely correct in C++11, with the 
introduction of "final" and "override".  Someone please chime in to clarify 
this bit.

Back to comp.lang.c++ | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Non virtual and inheritance Sensei <sensei_s_mail_is_at@me.com> - 2012-10-18 13:55 +0200
  Re: Non virtual and inheritance Nobody <nobody@nowhere.com> - 2012-10-18 13:29 +0100
    Re: Non virtual and inheritance Juha Nieminen <nospam@thanks.invalid> - 2012-10-19 09:39 +0000
      Re: Non virtual and inheritance Nobody <nobody@nowhere.com> - 2012-10-19 15:01 +0100
        Re: Non virtual and inheritance Juha Nieminen <nospam@thanks.invalid> - 2012-10-19 16:01 +0000
  Re: Non virtual and inheritance Rui Maciel <rui.maciel@gmail.com> - 2012-10-18 14:49 +0100
  Re: Non virtual and inheritance Luca Risolia <luca.risolia@studio.unibo.it> - 2012-10-18 20:06 +0200
  Re: Non virtual and inheritance Paavo Helde <myfirstname@osa.pri.ee> - 2012-10-18 14:40 -0500
  Re: Non virtual and inheritance Juha Nieminen <nospam@thanks.invalid> - 2012-10-19 09:41 +0000

csiph-web