I got a situation like this:
struct Foo
{
void Barry() { }
};
struct Bar : private Foo
{
template <class F> void Bleh(F Func) { Func(); }
};
struct Fooey : public Bar
{
void Blah() { Foo f; Bar::Bleh(std::bind(&Foo::Barry, &f)); }
};
And it doesn't compile (g++ 4.7.3). With error:
test.cpp: In member function ‘void Fooey::Blah()’:
test.cpp:4:1: error: ‘struct Foo Foo::Foo’ is inaccessible
test.cpp:15:23: error: within this context
test.cpp:4:1: error: ‘struct Foo Foo::Foo’ is inaccessible
test.cpp:15:47: error: within this context
However, if I do this:
class Fooey;
void DoStuff(Fooey* pThis);
struct Fooey : public Bar
{
void Blah() { DoStuff(this); }
};
void DoStuff(Fooey* pThis)
{
Foo f;
pThis->Bleh(std::bind(&Foo::Barry, &f));
}
It compiles just fine. What is logic behind this?
Here
struct Fooey : public Bar
{
void Blah() { Foo f; Bar::Bleh(std::bind(&Foo::Barry, &f)); }
};
name lookup for Foo finds the base class of Bar which is inaccesible because Bar inherits privately.
To fix it, qualify the name fully:
void Blah() { ::Foo f; Bar::Bleh(std::bind(&::Foo::Barry, &f)); }
The problem is that, inside Foo or any class derived from it, Foo is the injected class name; a name scoped inside Foo, which hides the same name for the class in the enclosing namespace. In this case, that is inaccessible due to the private inheritance.
You can work around this by explicitly referring to the name in the namespace, in this case ::Foo. Unfortunately, that will break if you move the class into another namespace.
It's a name conflict. For each inherited type, you get a member of that name in your own class. To access the actual type, you need to refer it by its qualified name (in this case, ::Foo).
This feature lets you use shadowed or overridden members of a base class from a derived class:
struct X
{
void Foo();
};
struct Y : public X
{
void Foo()
{
X::Foo(); // calls X's implementation of Foo
}
};
But it does mean that if you mean X as in struct X, you need to qualify it with its full name, calling it ::X.
When you inherit Bar from Foo with private inheritance, you make all of Foo's member data/functions private. So when you inherit Fooey from Bar, it cannot access any of Foo's members.
For more details on private inheritance: http://www.parashift.com/c++-faq/access-rules-with-priv-inherit.html
struct Fooey : public Bar
{
void Blah() { Foo f; Bar::Bleh(std::bind(&::Foo::Barry, &f)); }
};
This block, which contains the scope "fix" also creates another Foo (that is, Fooey already has a Foo object via its inheritance with Bar - this is creating another one and binding its Barry).
Related
Is there any way to avoid cast when calling a base class template function from a derived class instance? Suppose the following:
class Foo
{
public:
virtual void quux() = 0;
template <class T> void quux() { ... }
};
class Bar : public Foo
{
public:
void quux() override {}
};
Then later on usage of class Bar:
Bar bar;
bar.quux<int>(); // error: type 'int' unexpected
static_cast<Foo&>(bar).quux<int>(); // OK
Any way to make this less obnoxious and make function quux callable on instances of Bar without having to duplicate the function signatures directly in Bar implementation? I'm aware of dependent name lookup, looking for a maintainable way to solve this for all derived classes.
Just add using Foo::quux;:
class Bar : public Foo
{
public:
using Foo::quux;
void quux() override {}
};
Let's suppose I have a namespace Foo and I have declared a class Bar inside of it with a constructor inheriting a class Base with its constructor along with some other class Baz with a publicly accessible method boo():
namespace Foo {
class Baz {
public:
void boo();
};
class Base {
public:
Base();
};
class Bar: public Base {
public:
Bar();
};
}
Now I want to define the Bar constructor in my implementation as follows:
Foo::Bar::Bar(): Foo::Base::Base() {
Foo::Baz::boo();
}
It appears as though it's OK to write it down like this:
Foo::Bar::Bar(): Base() {
Baz::boo();
}
Meaning that once I specify the namespace in Foo::Bar::Bar() explicitly, there is no need to specify it later in the definition of this method.
Does it work like that everywhere from the explicit mentioning of the namespace up to the end of the definition?
If we look at your Bar constructor definition:
Foo::Bar::Bar(): Base() {
Baz::boo();
}
Once the declaration-part of the constructor (Foo:::Bar::Bar) have been read by the compiler, it knows the scope and it's no longer needed.
A more interesting example would be e.g.
namespace Foo
{
struct Baz {};
struct Bar
{
Baz fun(Baz);
};
}
Foo::Baz Foo::Bar::fun(Baz)
{
// Irrelevant...
}
Now, for the definition of the structure itself, Baz doesn't need any namespace-qualifier since it's defined in the namespace and all the symbols of the namespace is available directly.
The definition of the function fun is a different. Because it's not defined inside the namespace, we need to fully qualify the Baz structure for the return type. And the same for the actual function-name. But then like before once that part is read and parsed by the compiler, it knows the scope and knows that the argument Baz is really Foo::Baz.
You can read more about name lookup in this reference.
First of all, sorry for the lengthy title. I encountered an issue, where the existence of a private base of the same type as a member shadows access to the member in a child class but not outside the child class definition. Look at the following code:
struct PrivateBase {};
struct Base : private PrivateBase {
// Member accessors.
PrivateBase* GetPrivateBase() { return &a; }
template<typename T>
T* GetPrivateBase() { return &a; }
// Free function accessors.
friend PrivateBase* FreeGetPrivateBase(Base* b) { return &(b->a); }
template<typename T>
friend T* FreeGetPrivateBase(Base* b);
private:
// This member has nothing to do with the PrivateBase base class.
PrivateBase a;
};
template<typename T>
T* FreeGetPrivateBase(Base* b) { return &(b->a); }
struct Child : public Base {
void SomeFunc() {
// Works!1!!.
GetPrivateBase();
// Doesn't work.
//GetPrivateBase<PrivateBase>(); // (1)
// Works!1!!.
FreeGetPrivateBase(this);
// Doesn't work.
//FreeGetPrivateBase<PrivateBase>(this);
}
};
int main() {
Child c;
// Works!1!!.
c.GetPrivateBase<PrivateBase>();
// Works!1!!.
FreeGetPrivateBase<PrivateBase>(&c);
return 0;
}
I've tried to compile this both, with g++-4.8.4 and clang++-3.7.1. With clang and (1) uncommented I get:
minimal.cc:30:20: error: 'PrivateBase' is a private member of 'PrivateBase'
GetPrivateBase<PrivateBase>();
^
minimal.cc:3:15: note: constrained by private inheritance here
struct Base : private PrivateBase {
^~~~~~~~~~~~~~~~~~~
minimal.cc:1:8: note: member is declared here
struct PrivateBase {};
^
The fun fact is that access to a works outside of Child and inside Child with the non-templated accessors. It also works inside Child with the templated accessors if I get rid of the private base class.
I would love to blame it on the compiler but unconventionally enough both contenders seem to agree. Could anybody explain the interplay between templated accessors, child scope and private base class? - Thanks.
Name lookup is done before access checking. Unqualified name lookup for PrivateBase within a member function of Child finds the injected class name of the PrivateBase base class, which is then found to be private, hence the error.
Using something like GetPrivateBase<::PrivateBase>(); inside SomeFunc() fixes the problem, because qualified name lookup now finds PrivateBase as a member of the global namespace, where it is accessible.
This is also why the calls in main work: main is not a member function, so unqualified name lookup for PrivateBase finds the namespace member.
Here a brief example of a code that works. It helps to introduce the actual question.
The specifiers for the visibility are the same used in the real code.
class Base {
public:
using foo = int;
virtual ~Base() { }
protected:
static foo bar() noexcept {
static foo v = 0;
return v++;
}
};
template<class Derived>
class Class: public Base {
static foo get() noexcept {
static foo v = bar();
return v;
}
};
int main() { }
It follows the previous example, even though slightly modified.
A template parameter has been added to the base class and the derived one has been updated accordingly.
This one doesn't compile.
template<typename T>
class Base {
public:
using foo = int;
virtual ~Base() { }
protected:
static foo bar() noexcept {
static foo v = 0;
return v++;
}
};
template<class Derived, typename T>
class Class: public Base<T> {
static foo get() noexcept {
static foo v = bar();
return v;
}
};
int main() { }
The error is quite clear indeed and the problem is not to solve it:
main.cpp:18:12: error: ‘foo’ does not name a type
static foo get() noexcept {
^
main.cpp:18:12: note: (perhaps ‘typename BaseComponent<T>::foo’ was intended)
The actual question is: why foo is not visible without a scope specifier in the second example?
I mean, Class is derived from Base<T>, that is (at least in my mind) a fully defined type, thus foo should be part of the base class and thus visible to the derived one, as it happens in the first example.
It follows an example that, according to what I guess of the problem, actually compiles and should not, or at least should behave like the previous one:
template <typename T>
struct B {
using foo = T;
};
struct D: public B<int> {
static foo bar;
};
int main() {
B<int> *b = new D;
}
Could it be due to the fact that the derived class is not a templated one in this case?
Honestly, it seems to me a bit strange, because the foo type is part of the base class that is still a templated one, so it shouldn't be much different from the previous one.
It goes without saying that I'm wrong, but I cannot figure out what's wrong in my thoughts.
Thank you in advance for the help.
That's because of name lookup rules. If your base class is a template, the unqualified name in base is not resolved. The reason is that later in your code you may have a template specialization of that base which doesn't define the name, or for which the name means something completely different. It's too complicated for the compiler to figure out whether you have a specialization, and if so, whether your name means the same thing in it. So it prefers to defer the name lookup. To make the compiler "believe you", then you need to either use a qualified name, or this->name instead (for members, not for typedefs), and the compiler will resolve the name.
I know that I can forward declare a class as follows:
class Foo;
// ... now I can use Foo*
However, can I do something like this:
class Bar {
public:
virtual void someFunc();
};
// ... somehow forward declare Class Foo as : public Bar here
someFunc(Foo* foo) {
foo -> someFunc();
}
class Foo: public Bar {
}
?
Thanks!
You can forward declare Bar as class Bar; and change the signature of someFunc to take a Bar* as parameter. Since someFunc() is a virtual method in the base class, it should work.
After your forward declaration Foo becomes an incomplete type and it will remain incomplete until you provide the definition of Foo.
While the Foo is incomplete any attempt to dereference a pointer to Foo is ill-formed. So to write
foo->someFunc();
you need to provide Foo's definition.