Accessing a protected member in a derived class

Discussion in 'C++' started by Tom, Jul 23, 2011.

  1. Tom

    Tom Guest

    Hi NG,

    The following example does not compile using g++. The compiler says
    "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    of the derived class:

    template<typename T>
    class MyBase
    {
    protected:
    int iMyVal;
    };

    template<typename T>
    class MyDerived : public MyBase<T>
    {
    void MyFunction()
    {
    // this->iMyVal = 10;
    iMyVal = 10;
    }
    };

    int main()
    {
    MyDerived<int> derived;
    return 0;
    }

    Using the line with the this-> works fine. After removing the template
    stuff the code compiles also fine without this->:

    class MyBase
    {
    protected:
    int iMyVal;
    };

    class MyDerived : public MyBase
    {
    void MyFunction()
    {
    iMyVal = 10;
    }
    };

    int main()
    {
    MyDerived derived;
    return 0;
    }

    My question is: Why do I need the "this->" in the first example. Why
    do I not need the this anymore when I remove the template parameter of
    the class?

    Tom
     
    Tom, Jul 23, 2011
    #1
    1. Advertising

  2. Tom wrote:

    > Hi NG,
    >
    > The following example does not compile using g++. The compiler says
    > "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    > of the derived class:
    >
    > template<typename T>
    > class MyBase
    > {
    > protected:
    > int iMyVal;
    > };
    >
    > template<typename T>
    > class MyDerived : public MyBase<T>
    > {
    > void MyFunction()
    > {
    > // this->iMyVal = 10;
    > iMyVal = 10;
    > }
    > };
    >
    > int main()
    > {
    > MyDerived<int> derived;
    > return 0;
    > }
    >
    > Using the line with the this-> works fine. After removing the template
    > stuff the code compiles also fine without this->:
    >


    "iMyVal" is an unqualified names. Unqualified name lookup won't look into
    base classes whose type depends on template parameters (such as "T", or
    "MyBase<T>").

    If you say "this->iMyVal" or "MyDerived::iMyVal", you are using class member
    access and qualified name lookup respectively. Those don't ignore dependent
    base classes, and will thus find "int iMyVal;" when instantiating
    "MyDerived<int>::MyFunction".
     
    Johannes Schaub, Jul 23, 2011
    #2
    1. Advertising

  3. On 7/23/2011 7:39 AM, Johannes Schaub wrote:
    > Tom wrote:
    >
    >> Hi NG,
    >>
    >> The following example does not compile using g++. The compiler says
    >> "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    >> of the derived class:
    >>
    >> template<typename T>
    >> class MyBase
    >> {
    >> protected:
    >> int iMyVal;
    >> };
    >>
    >> template<typename T>
    >> class MyDerived : public MyBase<T>
    >> {
    >> void MyFunction()
    >> {
    >> // this->iMyVal = 10;
    >> iMyVal = 10;
    >> }
    >> };
    >>
    >> int main()
    >> {
    >> MyDerived<int> derived;
    >> return 0;
    >> }
    >>
    >> Using the line with the this-> works fine. After removing the template
    >> stuff the code compiles also fine without this->:
    >>

    >
    > "iMyVal" is an unqualified names. Unqualified name lookup won't look into
    > base classes whose type depends on template parameters (such as "T", or
    > "MyBase<T>").
    >
    > If you say "this->iMyVal" or "MyDerived::iMyVal", you are using class member
    > access and qualified name lookup respectively. Those don't ignore dependent
    > base classes, and will thus find "int iMyVal;" when instantiating
    > "MyDerived<int>::MyFunction".
    >


    To the OP:
    http://www.parashift.com/c -faq-lite/templates.html#faq-35.19

    To Johannes:
    http://www.parashift.com/c -faq-lite/how-to-post.html#faq-5.5

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 23, 2011
    #3
  4. Victor Bazarov wrote:

    > On 7/23/2011 7:39 AM, Johannes Schaub wrote:
    >> Tom wrote:
    >>
    >>> Hi NG,
    >>>
    >>> The following example does not compile using g++. The compiler says
    >>> "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    >>> of the derived class:
    >>>
    >>> template<typename T>
    >>> class MyBase
    >>> {
    >>> protected:
    >>> int iMyVal;
    >>> };
    >>>
    >>> template<typename T>
    >>> class MyDerived : public MyBase<T>
    >>> {
    >>> void MyFunction()
    >>> {
    >>> // this->iMyVal = 10;
    >>> iMyVal = 10;
    >>> }
    >>> };
    >>>
    >>> int main()
    >>> {
    >>> MyDerived<int> derived;
    >>> return 0;
    >>> }
    >>>
    >>> Using the line with the this-> works fine. After removing the template
    >>> stuff the code compiles also fine without this->:
    >>>

    >>
    >> "iMyVal" is an unqualified names. Unqualified name lookup won't look into
    >> base classes whose type depends on template parameters (such as "T", or
    >> "MyBase<T>").
    >>
    >> If you say "this->iMyVal" or "MyDerived::iMyVal", you are using class
    >> member access and qualified name lookup respectively. Those don't ignore
    >> dependent base classes, and will thus find "int iMyVal;" when
    >> instantiating "MyDerived<int>::MyFunction".
    >>

    >
    > To the OP:
    > http://www.parashift.com/c -faq-lite/templates.html#faq-35.19
    >
    > To Johannes:
    > http://www.parashift.com/c -faq-lite/how-to-post.html#faq-5.5
    >


    The FAQ has it subtly wrong. Which is why I didn't gave him the FAQ entry.
    Where the Standard says that the base declaration is not found because the
    name is unqualified, the FAQ says that the declaration is not found because
    the name is non-dependent. This is a common misconception (I notified the
    FAQ author about this, and he noted that problem and thanked to me. But last
    time I checked, he hadn't fixed this problem yet).
     
    Johannes Schaub, Jul 23, 2011
    #4
  5. Tom

    Tom Guest

    On 23 Jul., 13:39, Johannes Schaub <>
    wrote:
    > Tom wrote:
    > > Hi NG,

    >
    > > The following example does not compile using g++. The compiler says
    > > "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    > > of the derived class:

    >
    > > template<typename T>
    > > class MyBase
    > > {
    > > protected:
    > >   int iMyVal;
    > > };

    >
    > > template<typename T>
    > > class MyDerived  : public MyBase<T>
    > > {
    > >   void MyFunction()
    > >   {
    > >     //    this->iMyVal = 10;
    > >     iMyVal = 10;
    > >   }
    > > };

    >
    > > int main()
    > > {
    > >   MyDerived<int> derived;
    > >   return 0;
    > > }

    >
    > > Using the line with the this-> works fine. After removing the template
    > > stuff the code compiles also fine  without this->:

    >
    > "iMyVal" is an unqualified names. Unqualified name lookup won't look into
    > base classes whose type depends on template parameters (such as "T", or
    > "MyBase<T>").
    >
    > If you say "this->iMyVal" or "MyDerived::iMyVal", you are using class member
    > access and qualified name lookup respectively. Those don't ignore dependent
    > base classes, and will thus find "int iMyVal;" when instantiating
    > "MyDerived<int>::MyFunction".


    Thanks for the explanations. So this is something which makes life a
    bit easier for the compiler, right? Or is there another reason to
    restrict the name lookup. I guess not because I think MS VS accepts
    the code without this.
     
    Tom, Jul 24, 2011
    #5
  6. On 23.07.2011 17:56, Johannes Schaub wrote:
    > Victor Bazarov wrote:
    >> On 7/23/2011 7:39 AM, Johannes Schaub wrote:
    >>> Tom wrote:
    >>>
    >>>> Hi NG,
    >>>>
    >>>> The following example does not compile using g++. The compiler says
    >>>> "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    >>>> of the derived class:
    >>>>
    >>>> template<typename T>
    >>>> class MyBase
    >>>> {
    >>>> protected:
    >>>> int iMyVal;
    >>>> };
    >>>>
    >>>> template<typename T>
    >>>> class MyDerived : public MyBase<T>
    >>>> {
    >>>> void MyFunction()
    >>>> {
    >>>> // this->iMyVal = 10;
    >>>> iMyVal = 10;
    >>>> }
    >>>> };
    >>>>
    >>>> int main()
    >>>> {
    >>>> MyDerived<int> derived;
    >>>> return 0;
    >>>> }
    >>>>

    [snip]
    >
    > The FAQ has it subtly wrong. Which is why I didn't gave him the FAQ entry.
    > Where the Standard says that the base declaration is not found because the
    > name is unqualified, the FAQ says that the declaration is not found because
    > the name is non-dependent. This is a common misconception


    Let's do a reality check.

    There is an error when "imMyVal" is a non-dependent name, and a concrete
    example has been given.

    Would there have been an error if instead of "imMyVal" there had been a
    dependent name (of course, it may then have to be of different syntactic
    form)?

    If the answer to that question is "no", then we have established that at
    least within the framework of this concrete example the dependency of
    the name corresponds directly to the error, i.e. that in this example
    dependent/non-dependent determines the error, as the FAQ says.

    If the answer, on the other hand, is "yes", then there should exist a
    concrete example of that?



    > (I notified the
    > FAQ author about this, and he noted that problem and thanked to me. But last
    > time I checked, he hadn't fixed this problem yet).


    I think that if you gave Marshall a concrete code example that was
    incompatible with the explanation in the FAQ, then he would update the
    FAQ promptly, unless he was prevented by e.g. health issues.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jul 25, 2011
    #6
  7. Tom

    Kouisawang Guest

    On Jul 23, 7:34 am, Tom <> wrote:
    > Hi NG,
    >
    > The following example does not compile using g++. The compiler says
    > "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    > of the derived class:
    >
    > template<typename T>
    > class MyBase
    > {
    > protected:
    >   int iMyVal;
    >
    > };
    >
    > template<typename T>
    > class MyDerived  : public MyBase<T>
    > {
    >   void MyFunction()
    >   {
    >     //    this->iMyVal = 10;
    >     iMyVal = 10;
    >   }
    >
    > };
    >
    > int main()
    > {
    >   MyDerived<int> derived;
    >   return 0;
    >
    > }
    >
    > Using the line with the this-> works fine. After removing the template
    > stuff the code compiles also fine  without this->:
    >
    > class MyBase
    > {
    > protected:
    >   int iMyVal;
    >
    > };
    >
    > class MyDerived  : public MyBase
    > {
    >   void MyFunction()
    >   {
    >     iMyVal = 10;
    >   }
    >
    > };
    >
    > int main()
    > {
    >   MyDerived derived;
    >   return 0;
    >
    > }
    >
    > My question is: Why do I need the "this->" in the first example. Why
    > do I not need the this anymore when I remove the template parameter of
    > the class?
    >
    > Tom


    Template is a compile time process. The pointer can access it without
    specifying the <T> because it goes directly to the memory where the
    parameter stored. If you don't wanna use pointer, try
    MyBase<T>::iMyVal. This will also happen to public members also.
     
    Kouisawang, Jul 25, 2011
    #7
  8. wrote:

    > On 23.07.2011 17:56, Johannes Schaub wrote:
    >> Victor Bazarov wrote:
    >>> On 7/23/2011 7:39 AM, Johannes Schaub wrote:
    >>>> Tom wrote:
    >>>>
    >>>>> Hi NG,
    >>>>>
    >>>>> The following example does not compile using g++. The compiler says
    >>>>> "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    >>>>> of the derived class:
    >>>>>
    >>>>> template<typename T>
    >>>>> class MyBase
    >>>>> {
    >>>>> protected:
    >>>>> int iMyVal;
    >>>>> };
    >>>>>
    >>>>> template<typename T>
    >>>>> class MyDerived : public MyBase<T>
    >>>>> {
    >>>>> void MyFunction()
    >>>>> {
    >>>>> // this->iMyVal = 10;
    >>>>> iMyVal = 10;
    >>>>> }
    >>>>> };
    >>>>>
    >>>>> int main()
    >>>>> {
    >>>>> MyDerived<int> derived;
    >>>>> return 0;
    >>>>> }
    >>>>>

    > [snip]
    >>
    >> The FAQ has it subtly wrong. Which is why I didn't gave him the FAQ
    >> entry. Where the Standard says that the base declaration is not found
    >> because the name is unqualified, the FAQ says that the declaration is not
    >> found because the name is non-dependent. This is a common misconception

    >
    > Let's do a reality check.
    >
    > There is an error when "imMyVal" is a non-dependent name, and a concrete
    > example has been given.
    >
    > Would there have been an error if instead of "imMyVal" there had been a
    > dependent name (of course, it may then have to be of different syntactic
    > form)?
    >


    Yes there would have been. The C++ Standard specifically says: Unqualified
    lookup ignores the dependent base classes both at the time of definition of
    the template and at instantiation of the template.


    > If the answer to that question is "no", then we have established that at
    > least within the framework of this concrete example the dependency of
    > the name corresponds directly to the error, i.e. that in this example
    > dependent/non-dependent determines the error, as the FAQ says.
    >
    > If the answer, on the other hand, is "yes", then there should exist a
    > concrete example of that?
    >


    I can't show an example using a function call, because if you make the name
    dependent, the rules for lookup of dependent function names dictate that
    unqualified lookup only consideres declarations of the definition context.
    Declarations visible only when instantiating are only considered by argument
    dependent lookup.

    But still, the following code contains a dependent name "f", and will ignore
    the dependent base class, even if the lookup for dependent function names
    would otherwise have looked-up in the scope of the class at the time of
    instantiation again.

    Example:

    template<typename T>
    struct A {
    void f(T) { }
    };

    template<typename T>
    struct B : A<T> {
    void g() {
    f(T());
    }
    };

    int main() { B<int> b; b.g(); }

    I can argue for my position by noting that the Standard doesn't define what
    happens to the dependent base class in the lookup within the definition
    context, if we would strike out the rule that unqualified lookup ignores
    dependent base class. The obvious interpretation would be to say "We have to
    look in the definition context into a base class that is dependent. Hence we
    have to delay lookup, waiting for it to become complete". The Standard
    doesn't need to handle this case because it explicitly says that unqualified
    lookup ignores dependent base classes, like I said above.

    In fact the "obvious interpretation" was spelled out in the C++98 Standard,
    which worded the rule differently (but to the same effect): It said that
    dependent base classes are not examined during lookup until the class is
    instantiated. The absence of a definition of the case of what happens to
    dependent base classes for lookup at the definition context was answered by
    that. Later DRs that were incorporated into C++03 noted that this is
    unnecessarily convoluted and easily leads to misinterpretations and changed
    it to simply say that unqualified lookup ignores dependent base classes.

    I can show non-call examples that prove my point:

    template<typename U>
    struct A {
    typedef int T;
    };

    template<typename T>
    struct B : A<T> {
    void f() {
    T t;
    }
    };

    The dependent name "T" is not found in the dependent base class, even though
    it would if ignoring dependent base classes would solely be done because of
    names being non-dependent. You may argue that lookup of names like "T" above
    is not redone at instantiation, but I think that the spec requires it to be,
    because "T" is type-dependent. Whether or not that is intuitive is another
    matter, though. C++98 explicitly ruled that the "T" declared in the
    dependent base class at instantiation time cannot hide the template
    parameter when lookup is done at instantiation again.
     
    Johannes Schaub, Jul 25, 2011
    #8
  9. On 25.07.2011 23:54, Johannes Schaub wrote:
    > wrote:
    >
    >> On 23.07.2011 17:56, Johannes Schaub wrote:
    >>> Victor Bazarov wrote:
    >>>> On 7/23/2011 7:39 AM, Johannes Schaub wrote:
    >>>>> Tom wrote:
    >>>>>
    >>>>>> Hi NG,
    >>>>>>
    >>>>>> The following example does not compile using g++. The compiler says
    >>>>>> "error: ‘iMyVal’ was not declared in this scope" in Method MyFunction
    >>>>>> of the derived class:
    >>>>>>
    >>>>>> template<typename T>
    >>>>>> class MyBase
    >>>>>> {
    >>>>>> protected:
    >>>>>> int iMyVal;
    >>>>>> };
    >>>>>>
    >>>>>> template<typename T>
    >>>>>> class MyDerived : public MyBase<T>
    >>>>>> {
    >>>>>> void MyFunction()
    >>>>>> {
    >>>>>> // this->iMyVal = 10;
    >>>>>> iMyVal = 10;
    >>>>>> }
    >>>>>> };
    >>>>>>
    >>>>>> int main()
    >>>>>> {
    >>>>>> MyDerived<int> derived;
    >>>>>> return 0;
    >>>>>> }
    >>>>>>

    >> [snip]
    >>>
    >>> The FAQ has it subtly wrong. Which is why I didn't gave him the FAQ
    >>> entry. Where the Standard says that the base declaration is not found
    >>> because the name is unqualified, the FAQ says that the declaration is not
    >>> found because the name is non-dependent. This is a common misconception

    >>
    >> Let's do a reality check.
    >>
    >> There is an error when "imMyVal" is a non-dependent name, and a concrete
    >> example has been given.
    >>
    >> Would there have been an error if instead of "imMyVal" there had been a
    >> dependent name (of course, it may then have to be of different syntactic
    >> form)?
    >>

    >
    > Yes there would have been. The C++ Standard specifically says: Unqualified
    > lookup ignores the dependent base classes both at the time of definition of
    > the template and at instantiation of the template.
    >
    >
    >> If the answer to that question is "no", then we have established that at
    >> least within the framework of this concrete example the dependency of
    >> the name corresponds directly to the error, i.e. that in this example
    >> dependent/non-dependent determines the error, as the FAQ says.
    >>
    >> If the answer, on the other hand, is "yes", then there should exist a
    >> concrete example of that?
    >>

    >
    > I can't show an example using a function call, because if you make the name
    > dependent, the rules for lookup of dependent function names dictate that
    > unqualified lookup only consideres declarations of the definition context.


    But isn't your example below an example using a function call?


    > Declarations visible only when instantiating are only considered by argument
    > dependent lookup.
    >
    > But still, the following code contains a dependent name "f", and will ignore
    > the dependent base class, even if the lookup for dependent function names
    > would otherwise have looked-up in the scope of the class at the time of
    > instantiation again.
    >
    > Example:
    >
    > template<typename T>
    > struct A {
    > void f(T) { }
    > };
    >
    > template<typename T>
    > struct B : A<T> {
    > void g() {
    > f(T());
    > }
    > };
    >
    > int main() { B<int> b; b.g(); }


    I think, send this example to Marshall?


    > I can argue for my position by noting that the Standard doesn't define what
    > happens to the dependent base class in the lookup within the definition
    > context, if we would strike out the rule that unqualified lookup ignores
    > dependent base class. The obvious interpretation would be to say "We have to
    > look in the definition context into a base class that is dependent. Hence we
    > have to delay lookup, waiting for it to become complete". The Standard
    > doesn't need to handle this case because it explicitly says that unqualified
    > lookup ignores dependent base classes, like I said above.
    >
    > In fact the "obvious interpretation" was spelled out in the C++98 Standard,
    > which worded the rule differently (but to the same effect): It said that
    > dependent base classes are not examined during lookup until the class is
    > instantiated. The absence of a definition of the case of what happens to
    > dependent base classes for lookup at the definition context was answered by
    > that. Later DRs that were incorporated into C++03 noted that this is
    > unnecessarily convoluted and easily leads to misinterpretations and changed
    > it to simply say that unqualified lookup ignores dependent base classes.
    >
    > I can show non-call examples that prove my point:
    >
    > template<typename U>
    > struct A {
    > typedef int T;
    > };
    >
    > template<typename T>
    > struct B : A<T> {
    > void f() {
    > T t;
    > }
    > };
    >
    > The dependent name "T" is not found in the dependent base class, even though
    > it would if ignoring dependent base classes would solely be done because of
    > names being non-dependent. You may argue that lookup of names like "T" above
    > is not redone at instantiation, but I think that the spec requires it to be,
    > because "T" is type-dependent. Whether or not that is intuitive is another
    > matter, though. C++98 explicitly ruled that the "T" declared in the
    > dependent base class at instantiation time cannot hide the template
    > parameter when lookup is done at instantiation again.


    Sounds like you were right.

    Also sounds like can'o'worms. :)

    Like, as if too much has been forcibly pressed into too few concepts, in
    the standard.


    Cheers,

    - Alf
     
    Alf P. Steinbach, Jul 26, 2011
    #9
    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. Shelly Adhikari
    Replies:
    3
    Views:
    373
    red floyd
    Sep 10, 2003
  2. Siemel Naran
    Replies:
    4
    Views:
    815
    Micah Cowan
    Jan 12, 2005
  3. Andy Lomax
    Replies:
    5
    Views:
    485
    John Carson
    Jun 30, 2005
  4. Dmitry
    Replies:
    0
    Views:
    401
    Dmitry
    Jun 9, 2008
  5. blangela
    Replies:
    8
    Views:
    675
    Erik Wikström
    Sep 26, 2008
Loading...

Share This Page