Calling a virtual method in a specific class

P

Pete Vidler

Hi folks,

I have a small hierarchy with a virtual method which is overridden in
the most derived class. I also have a method that needs to call two
versions of this.. the most derived and the base class:

#include <iostream>

struct A
{
virtual void Foo() { std::cout << "A::MyFunc" << std::endl; }
};

template< class AType >
struct B : public AType
{
void Bar() { Foo(); AType::Foo(); }
};

struct C : public B< A >
{
virtual void Foo() { std::cout << "C::MyFunc" << std::endl; }
};

int main()
{
B< A >* b = new C;
b->Bar();
delete b;
}

This works fine on gcc-3.3.3. I just read in the changes for the new
version of gcc (http://gcc.gnu.org/gcc-3.4/changes.html) that this is no
longer acceptable (and is unacceptable in standard C++).

Specifically -- "In a template definition, unqualified names will no
longer find members of a dependent base". So B::Bar would have to change to:

void Bar() { this->Foo(); this->AType::Foo(); }

My question is, is this legal C++? I'm hoping it will produce the output:

C::MyFunc
A::MyFunc

And it does on my current compiler, but is it standard C++?

Thanks,
-- Pete
 
A

Alf P. Steinbach

* Pete Vidler said:
I have a small hierarchy with a virtual method which is overridden in
the most derived class. I also have a method that needs to call two
versions of this.. the most derived and the base class:

#include <iostream>

struct A
{
virtual void Foo() { std::cout << "A::MyFunc" << std::endl; }
};

template< class AType >
struct B : public AType
{
void Bar() { Foo(); AType::Foo(); }
};

struct C : public B< A >
{
virtual void Foo() { std::cout << "C::MyFunc" << std::endl; }
};

int main()
{
B< A >* b = new C;
b->Bar();
delete b;
}

This works fine on gcc-3.3.3. I just read in the changes for the new
version of gcc (http://gcc.gnu.org/gcc-3.4/changes.html) that this is no
longer acceptable (and is unacceptable in standard C++).

Specifically -- "In a template definition, unqualified names will no
longer find members of a dependent base". So B::Bar would have to change to:

void Bar() { this->Foo(); this->AType::Foo(); }

My question is, is this legal C++? I'm hoping it will produce the output:

C::MyFunc
A::MyFunc

And it does on my current compiler, but is it standard C++?

Yes. This was discussed here very recently. I suggested a 'using'
declaration, but didn't know why or how it worked; someone else (sorry,
don't remember who) then explained the whole thing -- namely dependent
name lookup -- and summarized three techniques: 'using' directive,
'this->' qualification, and 'ClassName::' qualification.

Classname qualification is of course no good for virtual calls.

And 'this->' qualification is not very practical.

So I suggest placing a few 'using'-directives here & there; in your
example


template< class AType >
struct B : public AType
{
using AType::Foo; // For the unqualified (virtual) call.
void Bar() { Foo(); AType::Foo(); }
};
 
A

Alf P. Steinbach

* Pete Vidler said:
void Bar() { this->Foo(); this->AType::Foo(); }

Sorry, didn't see that first time around.

The second 'this->' qualification is entirely superflous (since the
class qualification already tells the compiler Foo is a dependent name)
and so it can and should be omitted.

I'd also omit the first 'this->' and use a 'using' statement instead.
 
R

Rob Williscroft

Alf P. Steinbach wrote in
[snip]


Yes. This was discussed here very recently. I suggested a 'using'
declaration, but didn't know why or how it worked; someone else
(sorry, don't remember who) then explained the whole thing -- namely
dependent name lookup -- and summarized three techniques: 'using'
directive, 'this->' qualification, and 'ClassName::' qualification.

Classname qualification is of course no good for virtual calls.

And 'this->' qualification is not very practical.

So I suggest placing a few 'using'-directives here & there; in your
example


template< class AType >
struct B : public AType
{
using AType::Foo; // For the unqualified (virtual) call.
void Bar() { Foo(); AType::Foo(); }
};

As much as I like the using alternative its also important to
note that it has other effects (often desirable):

- Un-hiding AType::Foo in the case where B also declares a Foo()
member.

- Access control, if AType::Foo is protected the above using
would also make AType::Foo() a public member of B.


As a side note I was inspired to try this:

#include <iostream>
#include <ostream>

struct X
{
protected:

typedef int type;
};

template <typename T > struct Y : T
{
using typename T::type;
type get() { return 1; }
};

int main()
{
using namespace std;

Y< X >::type i = 3;
Y< X > yx;

cerr << i << ", " << yx.get() << '\n';
}

MS VC 7.1 and CBuilderX (prerelease) both accepted the code, gcc 3.2.3
(MingW) objected to the 'using typename ...' and gcc 3.4 (prerelease)
was ok until I added the get() member function.

Oh well back too typedef typename ...

Rob.
 
P

Pete Vidler

Alf said:
Sorry, didn't see that first time around.

The second 'this->' qualification is entirely superflous (since the
class qualification already tells the compiler Foo is a dependent name)
and so it can and should be omitted.

I'd also omit the first 'this->' and use a 'using' statement instead.

Okay, thanks.

-- Pete
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,164
Messages
2,570,898
Members
47,439
Latest member
shasuze

Latest Threads

Top