Why doesn't this multiple virtual inheritance code compile?

Discussion in 'C++' started by Chris Stankevitz, Jan 2, 2012.

  1. My intention is to
    - Create an abstract base class "Shape" that must be an "Observer"
    - Create an class "Square" that is a "Shape" and also an
    "ObserverImp"

    I thought I could do this like so:

    struct Observer
    {
    virtual void Notify() = 0;
    };

    struct ObserverImp : public Observer
    {
    void Notify() {}
    };

    struct Shape : public virtual Observer
    {
    };

    struct Square : public Shape, public ObserverImp
    {
    };

    Shape* ShapeFactory()
    {
    return new Square;
    }

    $ g++ -Wall -c test.cpp
    test.cpp: In function 'Shape* ShapeFactory()':
    test.cpp:21:14: error: cannot allocate an object of abstract type
    'Square'
    test.cpp:16:1: note: because the following virtual functions are
    pure within 'Square':
    test.cpp:3:16: note: virtual void Observer::Notify()
    test.cpp:22:1: warning: control reaches end of non-void function

    Q: How can I do this using c++?

    Thank you,

    Chris
     
    Chris Stankevitz, Jan 2, 2012
    #1
    1. Advertising

  2. On Jan 2, 1:36 pm, Paavo Helde <> wrote:
    > You could try to make this 'public virtual Observer'.


    Thank you, yes I overlooked this. Although this does not help the
    compile problem.

    > That said, I'm not at all convinced that virtual inheritance is the right
    > approach here.


    Me too -- if it doesn't compile, it probably is not the correct
    approach!

    How would you go about accomplishing this with C++, if it is possible:
    - Create an abstract base class "Shape" that must be an "Observer"
    - Create an class "Square" that is a "Shape" and uses "ObserverImp"
    to implement the "Observer" behavior.

    Thank you,

    Chris
     
    Chris Stankevitz, Jan 2, 2012
    #2
    1. Advertising

  3. On Jan 2, 2:23 pm, Robert Wessel <> wrote:
    > Instantiating Square requires instantiating both an Observer and
    > ObserverImp under the hood.


    Yes, apparently so. I naively thought using "virtual inheritance"
    would make it so that both base classes need not be instantiated.

    > The obvious solution is to add an
    > implementation of the required function to Square:


    I am trying to avoid that particular obvious solution as it involves
    me typing the same code in all of my Shape implementations. Plus I've
    already written that code: it's in ObserverImp.

    Thank you,

    Chris
     
    Chris Stankevitz, Jan 2, 2012
    #3
  4. Chris Stankevitz

    Ian Collins Guest

    On 01/ 3/12 11:41 AM, Chris Stankevitz wrote:
    > On Jan 2, 1:36 pm, Paavo Helde<> wrote:
    >> You could try to make this 'public virtual Observer'.

    >
    > Thank you, yes I overlooked this. Although this does not help the
    > compile problem.
    >
    >> That said, I'm not at all convinced that virtual inheritance is the right
    >> approach here.

    >
    > Me too -- if it doesn't compile, it probably is not the correct
    > approach!
    >
    > How would you go about accomplishing this with C++, if it is possible:
    > - Create an abstract base class "Shape" that must be an "Observer"
    > - Create an class "Square" that is a "Shape" and uses "ObserverImp"
    > to implement the "Observer" behavior.


    If you don't actually require dynamic binding, you could make Observer a
    template with Imp as it's parameter:

    template <typename Imp> struct Observer
    {
    void Notify() { Imp::notify(); }
    };

    struct Imp
    {
    void Notify() {}
    };

    struct Shape : Observer<Imp>
    {
    };

    struct Square : Shape
    {
    };

    --
    Ian Collins
     
    Ian Collins, Jan 2, 2012
    #4
  5. On 02.01.2012 21:16, Chris Stankevitz wrote:
    > My intention is to
    > - Create an abstract base class "Shape" that must be an "Observer"
    > - Create an class "Square" that is a "Shape" and also an
    > "ObserverImp"
    >
    > I thought I could do this like so:
    >
    > struct Observer
    > {
    > virtual void Notify() = 0;
    > };
    >
    > struct ObserverImp : public Observer
    > {
    > void Notify() {}
    > };


    Use virtual inheritance for the interface (that is for `Observer`).


    > struct Shape : public virtual Observer
    > {
    > };
    >
    > struct Square : public Shape, public ObserverImp
    > {
    > };


    Technically OK.


    > Shape* ShapeFactory()


    Please use different naming conventions for types and functions.


    > {
    > return new Square;
    > }


    No. Forget the Java-isms. You don't need any
    factory-manager-singleton-envelope-blahblah complication.

    Or at least, if you absolutely have to code Java in C++, then do it
    properly.

    E.g., then return a smart pointer, not a raw pointer.


    > $ g++ -Wall -c test.cpp
    > test.cpp: In function 'Shape* ShapeFactory()':
    > test.cpp:21:14: error: cannot allocate an object of abstract type
    > 'Square'
    > test.cpp:16:1: note: because the following virtual functions are
    > pure within 'Square':
    > test.cpp:3:16: note: virtual void Observer::Notify()
    > test.cpp:22:1: warning: control reaches end of non-void function
    >
    > Q: How can I do this using c++?


    See above.

    It then compiles nicely, and corresponds directly to Java-like
    implementation inheritance for an interface.

    If you run into any problems then please post to a new thread with your
    exact code and compiler invocation.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jan 2, 2012
    #5
  6. On Jan 2, 3:56 pm, "Paul" <pchrist<nospam>> wrote:
    > class Shape:public observerImp{};


    Paul,

    I do not want all Shapes to be observerImps. I want all shapes to be
    observers. I suspect what I want is not possible with c++.

    Thank you,

    Chris
     
    Chris Stankevitz, Jan 3, 2012
    #6
  7. On Jan 2, 3:46 pm, "Alf P. Steinbach" <alf.p.steinbach
    > wrote:
    > If you run into any problems then please post to a new thread with your
    > exact code and compiler invocation.


    Alf,

    I attempted what you suggested (minus the style, factory, auto_ptr,
    and new thread suggestions). What I came up with did not compile.
    (Compiler invocation appears below). Would you please tell me how I
    can modify this code so that it compiles and implements:
    - Create an abstract base class "Shape" that must be an "Observer"
    - Create a class "Square" that is a "Shape" and uses "ObserverImp" to
    implement the "Observer" behavior.

    Thank you,

    Chris

    //-----

    struct Observer
    {
    virtual void Notify() = 0;
    };

    struct ObserverImp : public virtual Observer
    {
    void Notify() {}
    };

    struct Shape : public Observer
    {
    };

    struct Square : public Shape, public ObserverImp
    {
    };

    Shape* ShapeFactory()
    {
    return new Square;
    }

    //-----

    $ g++ -Wall -c test.cpp
    test.cpp: In function 'Shape* ShapeFactory()':
    test.cpp:21:14: error: cannot allocate an object of abstract type
    'Square'
    test.cpp:16:1: note: because the following virtual functions are
    pure within 'Square':
    test.cpp:3:16: note: virtual void Observer::Notify()
    test.cpp:22:1: warning: control reaches end of non-void function
     
    Chris Stankevitz, Jan 3, 2012
    #7
  8. Chris Stankevitz <> wrote:
    > test.cpp: In function 'Shape* ShapeFactory()':
    > test.cpp:21:14: error: cannot allocate an object of abstract type
    > 'Square'
    > test.cpp:16:1: note: because the following virtual functions are
    > pure within 'Square':
    > test.cpp:3:16: note: virtual void Observer::Notify()


    How about you try to read what the compiler is telling you? It's telling
    to the exact reason why you cannot instantiate the class: You have a pure
    virtual function in the base class that is not implemented in the derived
    class.
     
    Juha Nieminen, Jan 3, 2012
    #8
  9. Chris Stankevitz

    Goran Guest

    On Jan 3, 8:20 am, Paavo Helde <> wrote:
    > Chris Stankevitz <> wrote innews::
    >
    > > On Jan 2, 1:36 pm, Paavo Helde <> wrote:
    > >> You could try to make this 'public virtual Observer'.

    >
    > > Thank you, yes I overlooked this.  Although this does not help the
    > > compile problem.

    >
    > Strange, compiles fine with my MSVC2010 and gcc (though MSVC issues a
    > strange warning):


    AFAICanSee, what Paavo suggested is __the__ solution for your
    conundrum. Comeau also (obviously) compiles this. Chris, what is the
    compiler error?

    Goran.
     
    Goran, Jan 3, 2012
    #9
  10. Chris Stankevitz

    Spike Guest

    Spike, Jan 3, 2012
    #10
  11. On 03.01.2012 05:25, Chris Stankevitz wrote:
    > I do not want all Shapes to be observerImps. I want all shapes to be
    > observers. I suspect what I want is not possible with c++.


    What you are going to do is to have a helper class OberserImp that
    implements the observer interface independently of the outer class. And
    you want to be able to use this helper class down in the class tree not
    only at the level of the interface reference in the class Shape.

    I know two solution for this in C++.

    1. The Java way.
    The equivalent of interfaces in Java and .NET are virtual abstract base
    classes in C++. If you want the Java behavior you always need to derive
    virtual from all interface like C++ classes.
    That was your approach except for the missing virtual at class Shape.

    2. An template implememtation helper.
    template <typename BASE>
    class ObserverImp : BASE
    {
    void Notify() {}
    };
    class Square : public ObserverImp<Shape>
    {
    };

    #1 has the disadvantage that it always requires another level of
    indirection to access interface members at run time, even if this is not
    required. And in real life this is required quite rarely.
    The performance impact of this indirection is usually no big deal, but
    the reduced possibilities for optimization and especially inlining could
    be relevant.


    Marcel
     
    Marcel Müller, Jan 3, 2012
    #11
  12. Chris Stankevitz

    Joe keane Guest

    In article <>,
    Chris Stankevitz <> wrote:
    > - Create an abstract base class "Shape" that must be an "Observer"
    > - Create an class "Square" that is a "Shape" and also an "ObserverImp"


    So a 'Shape' is an 'Observer', and a 'Square' is a type of 'Shape'.

    Now you want something that is an 'ObserverImp' [and it is square].
    Wouldn't it make more sense to call it a 'SquareImp'?
     
    Joe keane, Jan 3, 2012
    #12
  13. On Jan 2, 11:20 pm, Paavo Helde <> wrote:
    > Strange, compiles fine with my MSVC2010 and gcc (though MSVC issues a
    > strange warning):


    Paavo,

    Thank you for your help and for posting the valid source in its
    entirety. I have it compiling now. The mistake I made was: missing
    "virtual" in the declaration for class Shape. "Virtual" must appear
    in the class declarations for "Shape" and "ObserverImp". Apparently I
    had trouble parsing people's "english" description of my mistake but I
    had no trouble parsing the c++ code in its entirety.

    The code that compiles and the g++ invocation appear below.

    Thank you again,

    Chris

    ===


    struct Observer
    {
    virtual void Notify() = 0;
    };

    struct ObserverImp : public virtual Observer
    {
    void Notify() {}
    };

    struct Shape : public virtual Observer
    {
    };

    struct Square : public Shape, public ObserverImp
    {
    };

    Shape* ShapeFactory()
    {
    return new Square;
    }

    ====

    $ g++ -Wall -c test.cpp
     
    Chris Stankevitz, Jan 3, 2012
    #13
  14. On Jan 3, 12:35 am, Spike <> wrote:
    > Your code was missing one virtual modifier.
    >
    > Also you need to declare the base classes destructors as virtual.
    > Seehttp://en.wikipedia.org/wiki/Virtual_function#Virtual_destructors
    > for an explanation.


    Spike,

    Thank you. I tried to dumb down my example to make the code easier to
    understand. My actual code has virtual destructors and, Alf will be
    happy to hear, a consistent style that differentiates class names from
    function names.

    Chris
     
    Chris Stankevitz, Jan 3, 2012
    #14
  15. On 03.01.2012 22:51, Leigh Johnston wrote:
    >
    > For good examples of using the same naming convention for both types and
    > functions see the C++ standard library.


    The standard library operates under conditions that normal code does not:

    (a) It is guaranteed to be used a lot by everybody.

    (a1) all serious users become familiar with the names. This means
    that for the standard library it is more important to reduce typing
    effort (having short names) than to reduce interpretation and
    recognition effort (having self-describing names). Aiming for the latter
    would just be wasted effort.

    (a2) since much of it is template based code, short names and terse
    coding style help to reduce compile times. look at the code written pjp
    (e.g. for visual c++'s standard library). it is horrible by the
    standards of ordinary application programming, where clarity is the main
    concern, but it it is near ideal for fast compilation.

    (a3) bugs are much more likely to surface early and repeatedly, than
    with ordinary application code. again this reduced the need for clarity.

    (b) It can be and in some parts has to be system- and compiler-specific.
    If some particular piece of code is not part of the developers have
    aimed to make portable (to reduce the total effort), then it can be
    written in any compiler- and system-dependent way, whatever the
    developer regards as easiest. This is generally not so for ordinary
    application code.

    In short, do not look to the standard library for naming and formatting
    conventions for ordinary application code.

    The standard library is not ordinary application code: it operates under
    a totally different set of rules.

    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jan 4, 2012
    #15
  16. Chris Stankevitz

    Ian Collins Guest

    On 01/ 4/12 02:19 PM, Leigh Johnston wrote:
    > On 04/01/2012 01:14, Alf P. Steinbach wrote:
    >> On 03.01.2012 22:51, Leigh Johnston wrote:
    >>>
    >>> For good examples of using the same naming convention for both types and
    >>> functions see the C++ standard library.

    >>
    >> The standard library operates under conditions that normal code does not:
    >>
    >> (a) It is guaranteed to be used a lot by everybody.
    >>
    >> (a1) all serious users become familiar with the names. This means that
    >> for the standard library it is more important to reduce typing effort
    >> (having short names) than to reduce interpretation and recognition
    >> effort (having self-describing names). Aiming for the latter would just
    >> be wasted effort.
    >>
    >> (a2) since much of it is template based code, short names and terse
    >> coding style help to reduce compile times. look at the code written pjp
    >> (e.g. for visual c++'s standard library). it is horrible by the
    >> standards of ordinary application programming, where clarity is the main
    >> concern, but it it is near ideal for fast compilation.
    >>
    >> (a3) bugs are much more likely to surface early and repeatedly, than
    >> with ordinary application code. again this reduced the need for clarity.
    >>
    >> (b) It can be and in some parts has to be system- and compiler-specific.
    >> If some particular piece of code is not part of the developers have
    >> aimed to make portable (to reduce the total effort), then it can be
    >> written in any compiler- and system-dependent way, whatever the
    >> developer regards as easiest. This is generally not so for ordinary
    >> application code.
    >>
    >> In short, do not look to the standard library for naming and formatting
    >> conventions for ordinary application code.
    >>
    >> The standard library is not ordinary application code: it operates under
    >> a totally different set of rules.

    >
    > There can only be one response to the above verbiage: LOL!


    Why?

    I've worked on a lot of projects with almost as many coding standards
    and I don't think the standard library naming conventions would be
    acceptable under any of them. All of my current clients have some form
    of different naming convention for types rule.

    --
    Ian Collins
     
    Ian Collins, Jan 4, 2012
    #16
  17. Chris Stankevitz

    Joe keane Guest

    In article <je096m$l1d$>,
    Alf P. Steinbach <> wrote:
    >The standard library operates under conditions that normal code does not:


    c) It has a precise specification, that is more or less set in stone.

    Often apps do not have much documentation [especially of internals], and
    what there is may be inaccurate or out of date. So it is important for
    the code to explain itself.

    I would not mind if the standard headers have -no- comments. So long as
    it works right...
     
    Joe keane, Jan 4, 2012
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. cppsks
    Replies:
    0
    Views:
    834
    cppsks
    Oct 27, 2004
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,078
    Smokey Grindel
    Dec 2, 2006
  3. Tony Johansson
    Replies:
    2
    Views:
    418
    Robben
    Aug 17, 2005
  4. Thomas Zangl
    Replies:
    11
    Views:
    548
    mlimber
    Jan 13, 2006
  5. Nagaraj
    Replies:
    1
    Views:
    892
    Lionel B
    Mar 1, 2007
Loading...

Share This Page