Get parent class function pointer

  • Thread starter Thread starter marco_segurini
  • Start date Start date
M

marco_segurini

Hi,

the following sample code shows a compiler error I get trying to build
some old code with the last CL compiler (vers 13.10.3077):

//----- begin
#include <iostream>

namespace ns
{
class base
{
public:
base() {}
virtual ~base() {}
protected:
void Call() { std::cout << "OK" << std::endl; }
};

class derived : public base
{
public:
void Start()
{
typedef void (ns::base::* typeCall)(void);
typeCall fnCall;
fnCall = &ns::base::Call; // this is the line # 21
(this->*fnCall)();
}
};
}


int main()
{
ns::derived d;
d.Start();

return 0;
}
//----- end

I get the following compiler message error at line 21:

main.cpp(21): error C2248: 'ns::base::Call' : cannot access protected
member declared in class 'ns::base'

Workaround: if I remove the ampersand all works fine.

I like to know if the line # 21 is really illegal.

thanks.
Marco.
 
I wouldn't like to trawl through the standard on this one, but I suspect
that the error is correct.

A derived class method is only allowed to access protected members in base
when base is acting as derived's base class. Thus:

class derived : public base
{
public:
void Start()
{
derived objA;
objA.Call (); // Compiles OK

base objB; // Or a different derived class
objB.Call (); // Compiler error
}
};

So to make your code compile, replace:

fnCall = &ns::base::Call;

with

fnCall = &ns::derived::Call;

which works even though Call () is not overridden in derived.

If you do have a derived implementation of Call, and you still want
base::Call, then

fnCall = &ns::derived::base::Call;

will do the trick, but only if Call () is non-virtual. If it is virtual, you
get derived::Call.

Hope this helps,

Jasper Kent.
 
marco_segurini said:
Thank you very much.

A last question: why

fnCall = /*&*/ns::base::Call; // line # 21 without ampersand

compile fine?

According to the standard, it should not. It's an MS extension to accept
it. Try compiling with -Za & see if it's then flagged as an error.

-cd
 
Jasper said:
I wouldn't like to trawl through the standard on this one, but I
suspect that the error is correct.

A derived class method is only allowed to access protected members in
base when base is acting as derived's base class. Thus:

class derived : public base
{
public:
void Start()
{
derived objA;
objA.Call (); // Compiles OK

base objB; // Or a different derived class
objB.Call (); // Compiler error
}
};

So to make your code compile, replace:

fnCall = &ns::base::Call;

with

fnCall = &ns::derived::Call;
Correct.


which works even though Call () is not overridden in derived.

If you do have a derived implementation of Call, and you still want
base::Call, then

fnCall = &ns::derived::base::Call;

This should produce the same error as the original - ns::base::Call is not
accessible through a pointer or reference to ns::base.

-cd
 
Carl Daniel said:
This should produce the same error as the original - ns::base::Call is not
accessible through a pointer or reference to ns::base.

Well it compiles fine on VC++ v7.
 
If it's good enough for you, a VC++ MVP, then why isn't it good enough for
VC++ compiler itself?
 
--------------------
From: (e-mail address removed) (marco_segurini)
Newsgroups: microsoft.public.dotnet.languages.vc
Subject: Get parent class function pointer
Date: 8 Sep 2003 02:55:54 -0700
Organization: http://groups.google.com/
Lines: 53
Message-ID: <[email protected]>
NNTP-Posting-Host: 62.110.81.102
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
X-Trace: posting.google.com 1063014955 12167 127.0.0.1 (8 Sep 2003 09:55:55 GMT)
X-Complaints-To: (e-mail address removed)
NNTP-Posting-Date: 8 Sep 2003 09:55:55 GMT
Path: cpmsftngxa06.phx.gbl!TK2MSFTNGP08.phx.gbl!news-out.cwix.com!newsfeed.cwix.co
m!newsfeed.frii.net!newsfeed.frii.net!140.99.99.194.MISMATCH!newsfeed1.easyn
ews.com!easynews.com!easynews!sn-xit-02!sn-xit-04!sn-xit-06!sn-xit-05!sn-xit
-09!supernews.com!postnews1.google.com!not-for-mail
Xref: cpmsftngxa06.phx.gbl microsoft.public.dotnet.languages.vc:28042
X-Tomcat-NG: microsoft.public.dotnet.languages.vc

Hi,

the following sample code shows a compiler error I get trying to build
some old code with the last CL compiler (vers 13.10.3077):

//----- begin
#include <iostream>

namespace ns
{
class base
{
public:
base() {}
virtual ~base() {}
protected:
void Call() { std::cout << "OK" << std::endl; }
};

class derived : public base
{
public:
void Start()
{
typedef void (ns::base::* typeCall)(void);
typeCall fnCall;
fnCall = &ns::base::Call; // this is the line # 21
(this->*fnCall)();
}
};
}


int main()
{
ns::derived d;
d.Start();

return 0;
}
//----- end

I get the following compiler message error at line 21:

main.cpp(21): error C2248: 'ns::base::Call' : cannot access protected
member declared in class 'ns::base'

Workaround: if I remove the ampersand all works fine.

I like to know if the line # 21 is really illegal.

thanks.
Marco.

Here's the reason from the ISO Standard:

[class.protected] 11.5 Protected member access
1 When a friend or a member function of a derived class references a
protected nonstatic member function or
protected nonstatic data member of a base class, an access check applies in
addition to those described earlier
in clause 11.102) Except when forming a pointer to member (5.3.1), the
access must be through a
pointer to, reference to, or object of the derived class itself (or any
class derived from that class) (5.2.5). If
the access is to form a pointer to member, *** the nested-name-specifier
shall name the derived class (or any
class derived from that class). ***

Note the part marked with "***". This is what the compiler is complaining
about.
 
Back
Top