private inheritance and ambiguous base

Discussion in 'C++' started by nguillot, Feb 23, 2011.

  1. nguillot

    nguillot Guest

    Hello.

    Here an example of is-implemented-in-term-of (or has-a) relation, with
    a private inheritance:
    (please, this is sample code to illustrate my question, don't suggest
    me to use composition, even if you would be right).
    every class that wants to log must inherit from the following class:

    class Loggable
    {
    protected:
    Loggable(std::string className) : className_(className) {}
    void Log(std::string text)
    {
    // a log function, for instance:
    std::cout << className_ << ": " << text << endl;
    }
    private:
    std::string className_;
    };

    Let's have a class A that wants to log:

    class A : private Loggable
    {
    public:
    A() : Loggable("A")
    {
    Log("blabla");
    }
    };

    So far, so good

    Now, let's have a class B that wants to log, and inherits from A:

    class B : private Loggable, public A
    {
    public:
    B() : Loggable("B")
    {
    Log("blbblb");
    }
    };

    It produces a warning:
    warning: direct base ‘Loggable’ inaccessible in ‘B’ due to ambiguity

    and an error:
    error: reference to ‘Log’ is ambiguous
    error: candidates are: void Loggable::Log(std::string)
    error: void Loggable::Log(std::string)

    A solution would to use virtual inheritance from Loggable, but I think
    it's not what I want:
    Maybe it's ambigous for the compiler which Loggable base to use when
    we use Log in B, but it's not: as I use private inheritance, the
    A::Log should'nt be available in B...

    So... is their another solution than virtual inheritance and
    composition?
    Another question: I don't understand why virtual inheritance fix the
    issue: in memory I still have an instance of loggable for A and
    another instance for B.

    Thank you for your answers.
     
    nguillot, Feb 23, 2011
    #1
    1. Advertising

  2. On 2/23/2011 4:49 PM, nguillot wrote:
    > Hello.
    >
    > Here an example of is-implemented-in-term-of (or has-a) relation, with
    > a private inheritance:
    > (please, this is sample code to illustrate my question, don't suggest
    > me to use composition, even if you would be right).
    > every class that wants to log must inherit from the following class:
    >
    > class Loggable
    > {
    > protected:
    > Loggable(std::string className) : className_(className) {}
    > void Log(std::string text)
    > {
    > // a log function, for instance:
    > std::cout<< className_<< ": "<< text<< endl;
    > }
    > private:
    > std::string className_;
    > };
    >
    > Let's have a class A that wants to log:
    >
    > class A : private Loggable
    > {
    > public:
    > A() : Loggable("A")
    > {
    > Log("blabla");
    > }
    > };
    >
    > So far, so good
    >
    > Now, let's have a class B that wants to log, and inherits from A:
    >
    > class B : private Loggable, public A
    > {
    > public:
    > B() : Loggable("B")
    > {
    > Log("blbblb");
    > }
    > };
    >
    > It produces a warning:
    > warning: direct base ‘Loggable’ inaccessible in ‘B’ due to ambiguity
    >
    > and an error:
    > error: reference to ‘Log’ is ambiguous
    > error: candidates are: void Loggable::Log(std::string)
    > error: void Loggable::Log(std::string)
    >
    > A solution would to use virtual inheritance from Loggable, but I think
    > it's not what I want:
    > Maybe it's ambigous for the compiler which Loggable base to use when
    > we use Log in B, but it's not: as I use private inheritance, the
    > A::Log should'nt be available in B...


    Access rights are not considered when names are resolved. Name
    resolution is what causes ambiguity. You can solve name resolution if
    you provide a hint to the compiler:

    B() : Loggable("B")
    {
    Loggable::Log("blbblb");
    }

    >
    > So... is their another solution than virtual inheritance and
    > composition?


    I think so. Try qualifying the name Log.

    > Another question: I don't understand why virtual inheritance fix the
    > issue: in memory I still have an instance of loggable for A and
    > another instance for B.


    Yes, but they share a single instance of Loggable.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Feb 23, 2011
    #2
    1. Advertising

  3. nguillot

    James Kanze Guest

    On Feb 23, 10:03 pm, Victor Bazarov <> wrote:
    > On 2/23/2011 4:49 PM, nguillot wrote:


    > > Here an example of is-implemented-in-term-of (or has-a) relation, with
    > > a private inheritance:
    > > (please, this is sample code to illustrate my question, don't suggest
    > > me to use composition, even if you would be right).
    > > every class that wants to log must inherit from the following class:


    > > class Loggable
    > > {
    > > protected:
    > > Loggable(std::string className) : className_(className) {}
    > > void Log(std::string text)
    > > {
    > > // a log function, for instance:
    > > std::cout<< className_<< ": "<< text<< endl;
    > > }
    > > private:
    > > std::string className_;
    > > };


    > > Let's have a class A that wants to log:


    > > class A : private Loggable
    > > {
    > > public:
    > > A() : Loggable("A")
    > > {
    > > Log("blabla");
    > > }
    > > };


    > > So far, so good


    > > Now, let's have a class B that wants to log, and inherits from A:


    > > class B : private Loggable, public A
    > > {
    > > public:
    > > B() : Loggable("B")
    > > {
    > > Log("blbblb");
    > > }
    > > };


    > > It produces a warning:
    > > warning: direct base Loggable inaccessible in B due to ambiguity


    > > and an error:
    > > error: reference to Log is ambiguous
    > > error: candidates are: void Loggable::Log(std::string)
    > > error: void Loggable::Log(std::string)


    > > A solution would to use virtual inheritance from Loggable, but I think
    > > it's not what I want:
    > > Maybe it's ambigous for the compiler which Loggable base to use when
    > > we use Log in B, but it's not: as I use private inheritance, the
    > > A::Log should'nt be available in B...


    > Access rights are not considered when names are resolved. Name
    > resolution is what causes ambiguity. You can solve name resolution if
    > you provide a hint to the compiler:


    > B() : Loggable("B")
    > {
    > Loggable::Log("blbblb");
    > }


    The whole point of the error message is that there is no way to
    qualify Loggable in a way which specifies the direct base of B.
    Loggable:: specifies the Loggable base of B, direct or indirect,
    and is ambiguous. The only way to work around the problem is to
    introduce an intermediate class, e.g.:

    struct LoggableForB : Loggable
    {
    LoggableForB() : Loggable("B") {}
    };

    class B : private LoggableForB, A
    {
    B()
    {
    LoggableForB::Log("blbblb");
    }
    };

    --
    James Kanze
     
    James Kanze, Feb 24, 2011
    #3
  4. nguillot

    itaj sherman Guest

    On Feb 23, 11:49 pm, nguillot <> wrote:
    > Hello.
    >
    > Here an example of is-implemented-in-term-of (or has-a) relation, with
    > a private inheritance:
    > (please, this is sample code to illustrate my question, don't suggest
    > me to use composition, even if you would be right).
    > every class that wants to log must inherit from the following class:
    >
    > class Loggable
    > {
    > protected:
    > Loggable(std::string className) : className_(className) {}
    > void Log(std::string text)
    > {
    > // a log function, for instance:
    > std::cout << className_ << ": " << text << endl;
    > }
    > private:
    > std::string className_;
    >
    > };
    >


    first inherit a TypedLoggable<T> instead directly Loggable:

    template< typename T >
    class TypedLoggable: public Loggable
    {
    protected:
    TypedLoggable( std::string className )
    :
    Loggable( className )
    {}

    TypedLoggable()
    :
    Loggable( typeid(T).name(); )
    {}

    public:
    };

    template< typename T >
    void Log2( T const& obj, std::string const& text )
    {
    static_cast< TypedLoggable<T> const& >( obj ).Log( text );
    }

    >
    > class A : private Loggable


    class A : private TypedLoggable<A>

    > {
    > public:
    > A() : Loggable("A")


    : TypedLoggable<A>( "A" )

    > {
    > Log("blabla");


    TypedLoggable<A>::Log( "dasda" );

    or

    Log2( *this, "blabla");

    > }
    >
    > };
    >
    > So far, so good
    >
    > Now, let's have a class B that wants to log, and inherits from A:
    >
    > class B : private Loggable, public A


    private TypedLoggable<B>

    > {
    > public:
    > B() : Loggable("B")
    > {
    > Log("blbblb");


    TypedLoggable<B>::Log( "dasda" );

    or

    Log2( *this, "blblbf" );

    > }
    >
    > };
    >


    Other members of Loggable might make sense in a hasA relation.
    But className_ could be a static member function of TypedLoggable<T>
    (that may use a singleton to keep the string per T). Keeping a string
    copy in every instance might be very wasteful.

    itaj
     
    itaj sherman, Feb 24, 2011
    #4
  5. nguillot

    itaj sherman Guest

    On Feb 24, 11:06 am, itaj sherman <> wrote:
    > On Feb 23, 11:49 pm, nguillot <> wrote:
    >


    >
    > > class A : private Loggable

    >
    > class A : private TypedLoggable<A>


    that will have to change: public TypedLoggable<A>

    > > Now, let's have a class B that wants to log, and inherits from A:

    >
    > > class B : private Loggable, public A

    >
    > private TypedLoggable<B>
    >


    public TypedLoggable<B>
     
    itaj sherman, Feb 24, 2011
    #5
  6. nguillot

    itaj sherman Guest

    On Feb 24, 10:26 am, James Kanze <> wrote:
    > On Feb 23, 10:03 pm, Victor Bazarov <> wrote:
    >
    >
    >
    >
    >
    > > On 2/23/2011 4:49 PM, nguillot wrote:
    > > > Here an example of is-implemented-in-term-of (or has-a) relation, with
    > > > a private inheritance:
    > > > (please, this is sample code to illustrate my question, don't suggest
    > > > me to use composition, even if you would be right).
    > > > every class that wants to log must inherit from the following class:
    > > > class Loggable
    > > > {
    > > > protected:
    > > >      Loggable(std::string className) : className_(className) {}
    > > >      void Log(std::string text)
    > > >      {
    > > >          // a log function, for instance:
    > > >          std::cout<<  className_<<  ": "<<  text<<  endl;
    > > >      }
    > > > private:
    > > >      std::string className_;
    > > > };
    > > > Let's have a class A that wants to log:
    > > > class A : private Loggable
    > > > {
    > > > public:
    > > >      A() : Loggable("A")
    > > >      {
    > > >          Log("blabla");
    > > >      }
    > > > };
    > > > So far, so good
    > > > Now, let's have a class B that wants to log, and inherits from A:
    > > > class B : private Loggable, public A
    > > > {
    > > > public:
    > > >      B() : Loggable("B")
    > > >      {
    > > >          Log("blbblb");
    > > >      }
    > > > };
    > > > It produces a warning:
    > > > warning: direct base Loggable inaccessible in B due to ambiguity
    > > > and an error:
    > > > error: reference to Log is ambiguous
    > > > error: candidates are: void Loggable::Log(std::string)
    > > > error:                 void Loggable::Log(std::string)
    > > > A solution would to use virtual inheritance from Loggable, but I think
    > > > it's not what I want:
    > > > Maybe it's ambigous for the compiler which Loggable base to use when
    > > > we use Log in B, but it's not: as I use private inheritance, the
    > > > A::Log should'nt be available in B...

    > > Access rights are not considered when names are resolved.  Name
    > > resolution is what causes ambiguity.  You can solve name resolution if
    > > you provide a hint to the compiler:
    > >     B() : Loggable("B")
    > >     {
    > >         Loggable::Log("blbblb");
    > >     }

    >
    > The whole point of the error message is that there is no way to
    > qualify Loggable in a way which specifies the direct base of B.
    > Loggable:: specifies the Loggable base of B, direct or indirect,
    > and is ambiguous.  The only way to work around the problem is to
    > introduce an intermediate class, e.g.:
    >


    Is B::Loggable::Log( "afa" ) stadard?

    itaj
     
    itaj sherman, Feb 24, 2011
    #6
    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. maxw_cc
    Replies:
    1
    Views:
    3,200
    Martijn van Steenbergen
    Dec 21, 2003
  2. Dave Theese
    Replies:
    4
    Views:
    424
    Jerry Coffin
    Aug 24, 2003
  3. qazmlp
    Replies:
    19
    Views:
    829
    Daniel T.
    Feb 4, 2004
  4. a eriksson
    Replies:
    1
    Views:
    311
    Victor Bazarov
    Aug 9, 2005
  5. karthikbalaguru
    Replies:
    9
    Views:
    1,070
Loading...

Share This Page