why can't I access this method via inheritance? [duplicate] - c++

This question already has answers here:
C++ method only visible when object cast to base class?
(7 answers)
Closed 8 years ago.
I have two simple classes, and wish to access the public method stuff by passing an int value. why can't I do that with an instance of Bar? Shouldn't it inherit the public method stuff. The type hinting gives the int a parameter, but it doesn't compile.
class Foo
{
public:
int a;
void stuff(int a){ std::cout << a << std::endl; }
};
class Bar : public Foo
{
protected:
void stuff() { std::cout << "hello world"; }
};
void main()
{
Bar b
b.stuff(3);
}

Because Bar::stuff hides Foo::stuff (only the name matters when overload resolution is performed, parameters are ignored).
You can :
Bring it into sope with a using declaration
Or alternatively, explicitly qualify the call e.g. b.Foo::stuff(3);.
Note :
main() must return an int.
#include <iostream>
class Foo
{
public:
int a;
void stuff(int a){ std::cout << a << std::endl; }
};
class Bar : public Foo
{
public:
using Foo::stuff;
protected:
void stuff() { std::cout << "hello world"; }
};
int main()
{
Bar b;
b.stuff(3);
}
Or :
int main()
{
Bar b;
b.Foo::stuff(3);
}

When looking up the name stuff, the one in Bar found first. Once that is found, the access privileges are checked. Since Bar::stuff is protected, you are not able to use it from main.
From the draft standard:
10.2 Member name lookup [class.member.lookup]
1 Member name lookup determines the meaning of a name (id-expression) in a class scope (3.3.7). Name lookup can result in an ambiguity, in which case the program is ill-formed. For an id-expression, name lookup begins in the class scope of this; for a qualified-id, name lookup begins in the scope of the nestedname-specifier. Name lookup takes place before access control (3.4, Clause 11).

In C++, name hiding can take place when one function in base class has the same name as one function in derived class.
Phases of the function call process
Name lookup
Overload resolution
Access control
Name lookup stops looking for other names as soon as it finds a name in derived class Bar. Therefore, Bar::stuff() hides any function with name stuff in Foo.
After the name lookup process,
overload resolution fails since there is no stuff(int) in Bar.
even though stuff() without int parameter is called, access control fails since stuff() is protected.

b.Foo::stuff(3);
Or, you can do a trick to access any protected:)
void main()
{
Bar b;
class BarAccess : public Bar { friend void main(); }
BarAccess * ba = reinterpret_cast<BarAccess *>(&b);
ba->stuff(3);
ba->stuff();
}

Related

C++ namespace collision in copy constructor

I have the following code:
namespace A {
struct Foo {
int a;
};
}
struct Foo {
int b;
};
struct Bar : public A::Foo {
Bar(Foo foo) {
c = foo.b;
}
int c;
};
C++ compilers complains at "c = foo.b" because A::Foo does not have a member named b.
If I change the type of Bar parameter with ::Foo it works.
My question is what is the rational behind this behaviour (I suppose it has to do with the fact that the inheritance makes Bar enter the A namespace but I cannot find any documentation to support this theory.
Every class has its name injected into it as a member. So you can name A::Foo::Foo. This is called the injected class name.
[class]
2 A class-name is inserted into the scope in which it is declared
immediately after the class-name is seen. The class-name is also
inserted into the scope of the class itself; this is known as the
injected-class-name. For purposes of access checking, the
injected-class-name is treated as if it were a public member name.
[basic.lookup]
3 The injected-class-name of a class is also considered to be a
member of that class for the purposes of name hiding and lookup.
Because unqualified name lookup of the argument type begins in the scope of the class Bar, it will continue into the scope of its base class to account for any member there. And it will find A::Foo::Foo as a type name.
If you want to use the global type name, simply qualify it by its surrounding (global) namespace.
Bar(::Foo foo) {
c = foo.b;
}
Which is doing fully qualified lookup in a scope where the injected class name doesn't appear.
For a followup "why" question see
Why is there an injected class name?
Not a complete answer, only code that shows (since it compiles) that Bar does not enter the namespace A. You can see that when inheriting from A::Foo1 there is no problem with ambiguity of Foo which would be different if this inheritance lets Bar enter A.
namespace A {
struct Foo {
int a;
};
struct Foo1 {
int a;
};
}
struct Foo {
int b;
};
struct Bar : public A::Foo1 {
Bar(Foo foo) {
c = foo.b;
}
int c;
};

Access to private nested class returned from member function

Please help me understand why it is possible for a class member function to return a private nested class object, and why it is then possible to call member functions on that private nested class, eg:
class Y
{
class X
{
public:
void f() { cout << "Hello World" << endl; }
};
public:
X g() { return X(); }
};
void h()
{
Y::X x; // Error, as expected: class Y::X is private.
x.f(); // Error.
Y y; // OK.
y.g().f(); // OK. But why???
}
I tested with GCC and Visual C++, and that last line compile on both. I cannot seem to find anything in the C++ standard that would make this valid. Any ideas why this works?
Edit:
Another observation:
void i()
{
Y y;
Y::X x2 = y.g(); // Error: class Y::X is private
x2.f(); // Error
auto x3 = y.g(); // OK
x3.f(); // OK
}
Making a nested class private doesn't mean external scopes can never use an instance of that class. Access specifiers affect names, and your main function never attempts to name Y::X.1 The only place where Y::X is named is within Y, which of course has access to its own private members. That the function returns an instance of Y::X to main isn't particularly relevant.
[C++14: 11/1]: A member of a class can be
private; that is, its name can be used only by members and friends of the class in which it is declared.
protected; that is, its name can be used only by members and friends of the class in which it is declared, by classes derived from that class, and by their friends (see 11.4).
public; that is, its name can be used anywhere without access restriction.
Admittedly, the standard does not have any text to explicitly unconfuse you and point out that access to the entities themselves is not controlled by these keywords, but that is definitely the intent and, ultimately, as far as the legalese goes.
1 It does name Y::X::f, but that name is public.
why it is possible for a class member function to return a private nested class object
A nested class is a class member too, and the member function has the access right on the private member.
and why it is then possible to call member functions on that private nested class
You're not using the private nested class name here, i.e. Y::X. And Y::X::f() is a public function, so it's possible to call it directly.
Here you can find the example that you are looking for. f1 is public, f2 is private and triggers the error you are expecting:
#include <iostream>
class Y
{
class X
{
public:
void f1() { std::cout << "Hello World" << std::endl; }
private:
void f2() { std::cout << "Hello World" << std::endl; }
};
public:
X g() { return X(); }
};
int main()
{
// Y::X x; // Error, as expected: class Y::X is private.
// x.f(); // Error.
Y y; // OK.
y.g().f1(); // OK. Because f1 is public.
y.g().f2(); // Error. Because f2 is private.
return 0;
}

Calling a static method by repeating the object name?

I have a singleton:
struct foo {
static foo& instance() {
static foo f;
return f;
}
};
When re-arranging some code I ended up with this statement "by error":
foo::foo::instance()
But this is deemed correct by my compiler (gcc 4.7). In fact, even foo::foo::foo::instance() compiles. Why?
It is due to "injected-name" — which means if foo is a class-name, and the same name "foo" is also injected into the class-scope which is why your code works. It is 100% Standard-conformant.
Here is one interesting example which shows the benefits of this feature:
namespace N
{
//define a class here
struct A
{
void f() { std::cout << "N::A" << std::endl; }
};
}
namespace M
{
//define another class with same name!
struct A
{
void f() { std::cout << "M::A" << std::endl; }
};
struct B : N::A //NOTE : deriving from N::A
{
B()
{
A a;
a.f(); //what should it print?
}
};
}
What should a.f() call? What is the type of a? Is it M::A or N::A? The answer is, N::A, not M::A.
Online Demo
It is because of name-injection, N::A is available inside the constructor of B without qualification. It also hides M::A, which remains outside the scope of B. If you want to use M::A, then you've to write M::A (or better ::M::A).
Because of [class]/2:
A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
So foo::foo is an injected class name, denoting foo itself.
Actually it's a bit more complicated: according to [class.qual]/2, foo::foo alone denotes a constructor of foo. In order to denote a class, it should either be preceded by struct (making it elaborated-type-specifier), or followed by :: (making it a nested-name-specifier - this is your case), or be a base-specifier (for example struct bar : foo::foo {};).
As stated in the other answers, the reason is name injection. To me, the main use case would be the following
struct B1 { void f(){} };
struct B2 { void f(){} };
struct D : B1, B2 { }
int main() {
D obj;
obj.f();
}
In main the call to f is ambiguous and won't compile. The way to be specific is a qualified call, ie
obj.B1::f();

using declarations and const overloads

Suppose I have two versions of operator-> (overloaded on const) in a base class. If I say
using Base::operator->;
in a derived class, will I get access to both versions or just the non-const one?
Same business as name hiding. It's all or nothing. Using declarations (7.3.3) bring a name, not a member.
ISO/IEC 14882 (2003), 7.3.3. 1/ A using-declaration introduces a name into the declarative
region in which the using-declaration appears. That name is a synonym
for the name of some entity declared elsewhere.
I encourage you to read 7.3.3, there are subtle things inside. You cannot using-declare a template, all the members refered by the name you using-declare must be accessible, the names are considerd for overload resolution alongside the names in the block the using declaration is found (ie. they don't hide anything), etc, etc.
You get access to all versions of a method/operator with the same name in that parent.
both. did you try it? (damn this answer is short: ah well, here is example:
#include <iostream>
#include <string>
struct bar
{
void foo() { std::cout << "non_c:foo()" << std::endl; }
void foo() const { std::cout << "c:foo()" << std::endl; }
};
class base
{
public:
bar* operator->() { return &b; }
bar const* operator->() const { return &b; }
private:
bar b;
};
class derived : public base
{
public:
using base::operator->;
};
int main(void)
{
const derived d = derived();
derived e;
d->foo();
e->foo();
}

C++ inheritance and function overriding

In C++, will a member function of a base class be overridden by its derived class function of the same name, even if its prototype (parameters' count, type and constness) is different? I guess this a silly question, since many websites says that the function prototype should be the same for that to happen; but why doesn't the below code compile? It's a very simple case of inheritance, I believe.
#include <iostream>
using std::cout;
using std::endl;
class A {};
class B {};
class X
{
public:
void spray(A&)
{
cout << "Class A" << endl;
}
};
class Y : public X
{
public:
void spray(B&)
{
cout << "Class B" << endl;
}
};
int main()
{
A a;
B b;
Y y;
y.spray(a);
y.spray(b);
return 0;
}
GCC throws
error: no matching function for call to `Y::spray(A&)'
note: candidates are: void Y::spray(B&)
The term used to describe this is "hiding", rather than "overriding". A member of a derived class will, by default, make any members of base classes with the same name inaccessible, whether or not they have the same signature. If you want to access the base class members, you can pull them into the derived class with a using declaration. In this case, add the following to class Y:
using X::spray;
That's so called 'hiding': Y::spray hides X::spray.
Add using directive:
class Y : public X
{
public:
using X::spray;
// ...
};
Classes are scopes and a class scope is nested in its parent. You have exactly the same behavior with other nested scopes (namespaces, blocks).
What happen is that when the name lookup searches for the definition of a name, it looks in the current namespace, then in the englobing namespace and so on until it find one definition; the search then stop (that's without taking into account the complications introduced by argument dependent name lookup -- the part of the rules which allows to use a function defined in the namespace of one of its argument).