privatising public member functions in derived classes.

Discussion in 'C++' started by Firkraag, Nov 21, 2007.

  1. Firkraag

    Firkraag Guest

    Hello

    #include <iostream>
    using std::cout;

    struct A {
    ~virtual A(){}
    virtual void foo(){ cout << "aaa\n"; }
    };

    struct B : A {
    private:
    virtual void foo(){ cout << "bbb\n"; }
    };

    void bar(A& ab)
    {
    ab.foo();
    }


    int main()
    {
    A a;
    B b;
    bar(b)
    }

    The above code works properly. As far as I know LSP is not being
    violated here. So why FAQ lite says this:
    http://www.parashift.com/c -faq-lite/proper-inheritance.html#faq-21.1
    Firkraag, Nov 21, 2007
    #1
    1. Advertising

  2. Firkraag wrote:
    > #include <iostream>
    > using std::cout;
    >
    > struct A {
    > ~virtual A(){}
    > virtual void foo(){ cout << "aaa\n"; }
    > };
    >
    > struct B : A {
    > private:
    > virtual void foo(){ cout << "bbb\n"; }
    > };
    >
    > void bar(A& ab)
    > {
    > ab.foo();
    > }
    >
    >
    > int main()
    > {
    > A a;
    > B b;
    > bar(b)
    > }
    >
    > The above code works properly. As far as I know LSP is not being
    > violated here. So why FAQ lite says this:
    > http://www.parashift.com/c -faq-lite/proper-inheritance.html#faq-21.1


    Compile this version of 'main' instead:

    template<class T> void callFoo(T &t)
    {
    t.foo();
    }

    int main()
    {
    B b;
    callFoo(b);
    }

    Now, the "duck typing" doesn't work, does it? LSP or not, what is
    the point of hiding 'foo' in 'B'? If you didn't intend to call the
    'foo' member directly, you ought to make it private and keep it
    private:

    struct A {
    private:
    virtual void foo() { cout << "aaa\n"; }
    public:
    void doFoo() { foo(); }
    };

    struct B : A {
    private:
    virtual void foo() { cout << "bbb\n"; }
    };

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Nov 21, 2007
    #2
    1. Advertising

  3. Firkraag

    werasm Guest

    On Nov 21, 5:12 am, "Victor Bazarov" <> wrote:

    > Now, the "duck typing" doesn't work, does it? LSP or not, what is
    > the point of hiding 'foo' in 'B'? If you didn't intend to call the
    > 'foo' member directly, you ought to make it private and keep it
    > private:
    >
    > struct A {
    > private:
    > virtual void foo() { cout << "aaa\n"; }
    > public:
    > void doFoo() { foo(); }
    > };
    >
    > struct B : A {
    > private:
    > virtual void foo() { cout << "bbb\n"; }
    > };


    To me this also seems a little pointless. If I want to convey
    to clientA that he may only call foo (or doFoo, for that
    matter), nothing stops client B from calling doFoo().

    What you are showing here above allows doFoo to dictate
    the order of the calling (template method) if there is
    an order, but it does not help with indicating which
    client is supposed to use the applicable interface.

    This however does:

    class A
    {
    friend class ClientOfA;
    virtual void foo() = 0;
    //...
    };

    or...

    class A
    {
    friend class ClientOfA;
    void doFoo(){ /*..call foo etc...*/ }
    virtual void foo() = 0;
    };

    class B{}; //All above private.
    werasm, Nov 21, 2007
    #3
  4. werasm wrote:
    > On Nov 21, 5:12 am, "Victor Bazarov" <> wrote:
    >
    >> Now, the "duck typing" doesn't work, does it? LSP or not, what is
    >> the point of hiding 'foo' in 'B'? If you didn't intend to call the
    >> 'foo' member directly, you ought to make it private and keep it
    >> private:
    >>
    >> struct A {
    >> private:
    >> virtual void foo() { cout << "aaa\n"; }
    >> public:
    >> void doFoo() { foo(); }
    >> };
    >>
    >> struct B : A {
    >> private:
    >> virtual void foo() { cout << "bbb\n"; }
    >> };

    >
    > To me this also seems a little pointless. If I want to convey
    > to clientA that he may only call foo (or doFoo, for that
    > matter), nothing stops client B from calling doFoo().


    But that's the whole point! The client of A or B or any other
    derived classes will have to always call doFoo() instead of
    'foo' (which can have different behaviour due to static or
    dynamic binding, IOW when calling through a pointer or directly
    for an object).

    > What you are showing here above allows doFoo to dictate
    > the order of the calling (template method)


    What template method? What are you talking about?

    > if there is
    > an order, but it does not help with indicating which
    > client is supposed to use the applicable interface.


    Huh?

    >
    > This however does:


    Does what, exactly?

    >
    > class A
    > {
    > friend class ClientOfA;
    > virtual void foo() = 0;
    > //...
    > };
    >
    > or...
    >
    > class A
    > {
    > friend class ClientOfA;
    > void doFoo(){ /*..call foo etc...*/ }
    > virtual void foo() = 0;
    > };
    >
    > class B{}; //All above private.


    The idiom of having all virtual interface private (pure or not)
    and having a public interface that just forwards the calls to the
    virtual function, is well known and commonly accepted in the
    industry. The main advantage is that there is a single point of
    call for all classes in the hierarchy, where you can put your
    pre- and post-conditions, and the virtual interface is never
    exposed for an occasional non-virtual call (where you can't tell
    just by looking which of the functions is going to be called).

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Nov 21, 2007
    #4
  5. Firkraag

    werasm Guest

    On Nov 21, 3:21 pm, "Victor Bazarov" <> wrote:
    > werasm wrote:


    > > To me this also seems a little pointless. If I want to convey
    > > to clientA that he may only call foo (or doFoo, for that
    > > matter), nothing stops client B from calling doFoo().

    >
    > But that's the whole point! The client of A or B or any other
    > derived classes will have to always call doFoo() instead of
    > 'foo' (which can have different behaviour due to static or
    > dynamic binding, IOW when calling through a pointer or directly
    > for an object).
    >
    > > What you are showing here above allows doFoo to dictate
    > > the order of the calling (template method)

    >
    > What template method? What are you talking about?


    http://en.wikipedia.org/wiki/Template_method

    More or less exactly what you are describing, but not
    good enough. The Template method pattern (sorry, I
    assumed you were familiar with the name) dictates
    the order of behaviour (Pre-conditions, Post-conditions
    etc.) iff there is an order (in the case of the example
    there was none).

    > > if there is
    > > an order, but it does not help with indicating which
    > > client is supposed to use the applicable interface.


    Client A wants to use Service A, and Client A dictates
    what it requires in terms of service. In the case
    of "Template Method" (what you have described) the
    service exists prior to the client using it (mostly),
    whereas often it works the other way around (in which
    case the pre/post conditions live in the calling code
    and not in the called code). The client often may
    no too little of the implementation to dicate anything
    apart from knowing what service it wants (which brings
    you back to pure virtual).

    > Huh?
    >
    > > This however does:

    >
    > Does what, exactly?


    This (or the example) allows the interface to be
    used only by the client that required it and gives
    the interface a single responsibility (in terms of
    one client only). For me this solves the problem
    of the OP better (in this particular case where
    doFoo does not provide any additional encapsulation
    as no pre/post conditions exist as the service
    implementation is unknown, and if they did exist,
    they could be performed in the calling code too).

    > The idiom of having all virtual interface private (pure or not)
    > and having a public interface that just forwards the calls to the
    > virtual function, is well known and commonly accepted in the
    > industry.


    Yes, I realize this (Its called "template method", not?, but this
    to me was not what the OP was looking for (perhaps he was, but
    I saw something else in his request).

    > The main advantage is that there is a single point of
    > call for all classes in the hierarchy, where you can put your
    > pre- and post-conditions, and the virtual interface is never
    > exposed for an occasional non-virtual call (where you can't tell
    > just by looking which of the functions is going to be called).


    I realize this. When I said "no point" I meant with respect to
    the case he specified (where pre/post conditions don't
    necessarily exist or are not known). Sometimes interfaces are merely
    used (in OOP) to convey intent and specify/dictate responsibility.
    In these cases the idiom you make mention of is lacking, whilst
    my example makes this clear.
    werasm, Nov 21, 2007
    #5
  6. Firkraag

    Ron Natalie Guest

    Firkraag wrote:

    > }
    >
    > The above code works properly. As far as I know LSP is not being
    > violated here. So why FAQ lite says this:
    > http://www.parashift.com/c -faq-lite/proper-inheritance.html#faq-21.1


    First the name is looked up.
    Then overloads for the found name are considered.
    Then the access for the best overload is considered.

    THEN, if the function is virtual, the final overrider is
    invoked.


    As with most everything else in C++, the thing that matters
    is the static declaration at the pointer of the call.
    Ron Natalie, Nov 23, 2007
    #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.

Share This Page