Not able to access inherited protected member?

Discussion in 'C++' started by Shriramana Sharma, Jun 27, 2013.

  1. Hello. Please consider the following minimized example for the problem I amfacing.

    >>>-------------------------------

    template < typename T >
    struct item {
    typedef item<T> * pointer ;
    pointer prev, next ;
    } ;

    template < typename ItemPtr >
    struct iterator_base {
    public:
    iterator_base () : ptr(0) {}
    protected:
    ItemPtr ptr ;
    explicit iterator_base ( ItemPtr p ) : ptr(p) {}
    } ;

    template < typename T >
    struct iterator : public iterator_base < item<T> * > {
    template<typename> friend class const_iterator ;
    } ;

    template < typename T >
    struct const_iterator : public iterator_base < const item<T> * > {
    const_iterator () {}
    const_iterator ( const iterator<T> & it ) : ptr(it.ptr) {}
    } ;

    int main () {
    iterator<int> it ;
    const_iterator<int> cit ;
    cit = it ;
    }
    <<<------------------------

    I get the error messages:

    >>>-------------------------------

    $ g++ -o iterator-base-minimal-2 iterator-base-minimal-2.cpp
    iterator-base-minimal-2.cpp: In constructor ‘const_iterator<T>::const_iterator(const iterator<T>&)’:
    iterator-base-minimal-2.cpp:28:46: error: class ‘const_iterator<T>’ does not have any field named ‘ptr’
    const_iterator ( const iterator<T> & it ) : ptr(it.ptr) {}
    ^
    $ clang++ -o iterator-base-minimal-2 iterator-base-minimal-2.cpp
    iterator-base-minimal-2.cpp:28:46: error: member initializer 'ptr' does notname a non-static data member or base class
    const_iterator ( const iterator<T> & it ) : ptr(it.ptr) {}
    ^~~~~~~~~~~
    1 error generated.
    <<<-------------------------------

    I am not sure why I can't access ptr which is a protected member of a parent class. OK so anyhow I thought I'll explicitly scope it by the base type and so I changed the const_iterator definition to:

    >>>-------------------------------

    template < typename T >
    struct const_iterator : public iterator_base < const item<T> * > {
    typedef iterator_base < const item<T> * > base ;
    const_iterator () {}
    const_iterator ( const iterator<T> & it ) : base::ptr(it.ptr) {}
    } ;
    <<<-------------------------------

    But now I get even more cryptic error messages:

    >>>-------------------------------

    $ g++ -o iterator-base-minimal-2 iterator-base-minimal-2.cpp
    iterator-base-minimal-2.cpp: In instantiation of ‘const_iterator<T>::const_iterator(const iterator<T>&) [with T = int]’:
    iterator-base-minimal-2.cpp:35:6: required from here
    iterator-base-minimal-2.cpp:28:62: error: no type named ‘ptr’ in ‘struct iterator_base<const item<int>*>’
    const_iterator ( const iterator<T> & it ) : base::ptr(it.ptr) {}
    ^
    $ clang++ -o iterator-base-minimal-2 iterator-base-minimal-2.cpp
    iterator-base-minimal-2.cpp:28:52: error: typename specifier refers to non-type member 'ptr' in 'iterator_base<const item<int> *>'
    const_iterator ( const iterator<T> & it ) : base::ptr(it.ptr) {}
    ^~~
    iterator-base-minimal-2.cpp:35:8: note: in instantiation of member function'const_iterator<int>::const_iterator' requested here
    cit = it ;
    ^
    iterator-base-minimal-2.cpp:13:10: note: referenced member 'ptr' is declared here
    ItemPtr ptr ;
    ^
    iterator-base-minimal-2.cpp:28:52: error: 'ptr' is a protected member of 'iterator_base<const item<int> *>'
    const_iterator ( const iterator<T> & it ) : base::ptr(it.ptr) {}
    ^
    iterator-base-minimal-2.cpp:13:10: note: must name member using the type ofthe current context 'const_iterator<int>'
    ItemPtr ptr ;
    ^
    2 errors generated.
    <<<-------------------------------

    I'm using GCC 4.8.1 and Clang 3.2 on Kubuntu Raring 64-bit. Can anyone please tell me what the problem is and how I can solve it? Thank you very much!
     
    Shriramana Sharma, Jun 27, 2013
    #1
    1. Advertising

  2. On 6/27/2013 2:10 PM, Shriramana Sharma wrote:
    > Hello. Please consider the following minimized example for the problem I am facing.
    >
    >>>> -------------------------------

    [...]

    Isn't it essentially the same as

    struct B {
    int a;
    };

    struct D : B {
    D(int a1) : a(a1) {}
    };

    ?

    You're trying to initialize (in the class initialiser list) a member
    that is not of that class. It's not allowed.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 27, 2013
    #2
    1. Advertising

  3. On Thursday, June 27, 2013 11:53:30 PM UTC+5:30, Victor Bazarov wrote:
    > You're trying to initialize (in the class initialiser list) a member
    > that is not of that class. It's not allowed.


    Thank you very much for your reply. So moving the base::ptr initialization to within the braces of the constructor fixes the situation for the above example.

    However this other minimal example seems to be able to take an initializer for the base class within the initializer list:

    template < typename T >
    struct iterator_base
    {
    protected:
    T * ptr ;
    } ;

    template < typename T >
    struct iterator : public iterator_base<T> {} ;

    template < typename T >
    struct const_iterator : public iterator_base<T>
    {
    typedef iterator_base<T> base ;
    const_iterator () : base::ptr(0) {}
    const_iterator ( const iterator<T> & it ) : base::ptr(it.ptr) {}
    } ;

    int main () {}

    Can you clarify what is the difference between this situation and the above? Thanks again!
     
    Shriramana Sharma, Jun 28, 2013
    #3
  4. Shriramana Sharma

    Öö Tiib Guest

    On Friday, 28 June 2013 04:43:44 UTC+3, Shriramana Sharma wrote:
    > Can you clarify what is the difference between this situation and the above? Thanks again!


    Can you clarify why you push those ill pieces of code?

    Situation is different since you do not instantiate the template
    (main is empty) and so the compiler is not required to diagnose it.
    Both examples are invalid C++. Try to write valid C++.
     
    Öö Tiib, Jun 28, 2013
    #4
  5. On Friday, June 28, 2013 8:16:43 AM UTC+5:30, Öö Tiib wrote:
    > Can you clarify why you push those ill pieces of code?


    I'm sorry but I don't understand what you mean by "pushing ill pieces of code". What am I "pushing" here?

    I am not a professional programmer but am trying to use C++ for some academic projects of mine. Is this the wrong forum to ask doubts about "why doesn't this work" in order to learn how to write C++ code correctly? It is obvious I do not have the experience you people do, which is why I am asking these simple (to you) questions here.

    > Situation is different since you do not instantiate the template
    > (main is empty) and so the compiler is not required to diagnose it.


    OK thanks -- this reply would have sufficed. I found that by instantiating the template the error is indeed flagged.

    > Both examples are invalid C++. Try to write valid C++.


    I *am* trying to write valid C++. For that I have to know what is valid C++(the standard is not all that simple to understand directly for everyone -- I hope you will not deny that). The very fact that the compiler rejects it already tells me that what I wrote is invalid C++. I am trying to understand *why* it is invalid C++.

    If you have the time and patience, help me and I am thankful for your help.If you don't have the time, just ignore my question. Please have patience with someone who is not as experienced as you.

    Thank you for your pointer though.
     
    Shriramana Sharma, Jun 28, 2013
    #5
  6. Shriramana Sharma

    Öö Tiib Guest

    On Friday, 28 June 2013 07:28:22 UTC+3, Shriramana Sharma wrote:
    > On Friday, June 28, 2013 8:16:43 AM UTC+5:30, Öö Tiib wrote:
    > > Can you clarify why you push those ill pieces of code?

    >
    > I'm sorry but I don't understand what you mean by "pushing ill pieces
    > of code". What am I "pushing" here?


    I am sorry, too, but Victor said that it is not allowed. Then you try to
    trick it otherwise, then third way. That I called "pushing". You are
    trying something in a strange way but what it is? What is your ultimate
    goal? Can you clarify why?

    > I am not a professional programmer but am trying to use C++ for some
    > academic projects of mine. Is this the wrong forum to ask doubts about
    > "why doesn't this work" in order to learn how to write C++ code correctly?


    It is correct forum but such path of learning C++ will not be easy. In fact
    learning C++ by trial and error is as hard as learning to fly airplane
    by trial and error.

    > > Situation is different since you do not instantiate the template
    > > (main is empty) and so the compiler is not required to diagnose it.

    >
    > OK thanks -- this reply would have sufficed. I found that by
    > instantiating the template the error is indeed flagged.


    Beware that C++ compiler may compile very lot of broken code without
    any diagnostics. C++ standard tells things like "code is ill-formed,
    no diagnostics required" or "behavior is undefined" about such code.
    Compilers (most notably CLang) still aim to diagnose as many
    errors as possible but it is hard.

    > > Both examples are invalid C++. Try to write valid C++.

    >
    > I *am* trying to write valid C++. For that I have to know what is valid
    > C++ (the standard is not all that simple to understand directly for
    > everyone -- I hope you will not deny that).


    Yes, also learning to fly airplane by studying its construction details
    is hard. There are only the formal technical details in standard. Audience
    is meant to be the C++ tool and compiler writers.

    Learn C++ by reading books that teach to use it. Most of us have several
    such books. Fine list of books:
    http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list

    > The very fact that the compiler rejects it already tells me that what I
    > wrote is invalid C++. I am trying to understand *why* it is invalid C++.


    It is rejecting because what you try is to break encapsulation. Constructor
    is meant for initializing virtual bases, bases and members. The bases and
    members however have full right to their own privacy and so are meant to
    initialize their details themselves:

    template < typename T >
    struct iterator_base
    {
    protected:
    iterator_base( T* p )
    : ptr(p)
    {}

    T* ptr;
    };

    template < typename T >
    struct const_iterator
    : public iterator_base<T>
    {
    const_iterator()
    : iterator_base( 0 )
    {}

    const_iterator( const_iterator<T> const& it )
    : iterator_base( it.ptr )
    {}
    };

    The protected members are exceptional. Most books suggest to have the
    data members private unless there are some rather good reasons.

    > If you have the time and patience, help me and I am thankful for your help.


    My question was not meant to insult you or to refuse to help you. It was
    to alert you to step back and analyze what you do. The way chosen seems
    to be non-optimal.
     
    Öö Tiib, Jun 28, 2013
    #6
  7. On Friday, June 28, 2013 11:08:13 AM UTC+5:30, Paavo Helde wrote:
    > > On Thursday, June 27, 2013 11:53:30 PM UTC+5:30, Victor Bazarov wrote:
    > >> You're trying to initialize (in the class initialiser list) a member
    > >> that is not of that class. It's not allowed.

    >
    > No, this is not fix, rather an abuse. In general, all data should be
    > private, IOW all initialization must be done by the class' own
    > constructors, not by constructors of some other class (derived or not).
    >
    > Make your data private, provide a constructor for the base class and use
    > this in the derived class constructor initialization list.


    Righto -- thank you for this pointer. Because Victor had initially insertedthe phrase "in the class initializer list", I thought it is OK to do the initialization within the braces. Now I understand that while that will be grammatically correct, it is inadvisable and unless it's a plain struct not intended for inheritance (the way D enforces) one should encapsulate data.
     
    Shriramana Sharma, Jul 8, 2013
    #7
  8. On Friday, June 28, 2013 6:23:57 PM UTC+5:30, Öö Tiib wrote:
    > I am sorry, too, but Victor said that it is not allowed. Then you try to
    > trick it otherwise, then third way. That I called "pushing".


    As I mention in my reply to Paavo above, the fact that Victor had included the phrase "in the member initializer list" (though it was within parans) lead me to only learn the fact that initialization of indirect sub-objects is not permissible in the member initializer list. Moving the same initialization to the braces compiled, so I thought that was OK.

    > You are
    > trying something in a strange way but what it is? What is your ultimate
    > goal? Can you clarify why?


    Heh there is no "ultimate goal" except to learn enough of the language for the project I am working on. :)

    > learning C++ by trial and error is as hard as learning to fly airplane
    > by trial and error.


    Well said. And I also take your point about not trying to learn C++ using the text of the standard.

    > It is rejecting because what you try is to break encapsulation. Constructor
    > is meant for initializing virtual bases, bases and members. The bases and
    > members however have full right to their own privacy and so are meant to
    > initialize their details themselves:


    Now I understand this.

    > My question was not meant to insult you or to refuse to help you. It was
    > to alert you to step back and analyze what you do. The way chosen seems
    > to be non-optimal.


    Thank you for the advice. It is truly appreciated. :)

    Shriramana.
     
    Shriramana Sharma, Jul 8, 2013
    #8
    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