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();
}
Related
It's a fact that you can explicitly access member variables (inside a member function, and not particularly a constructor) using this syntax : this->member_name (i.e. to distinguish with a function argument with the same name).
Besides this, I thought that the syntax ClassName::static_member was reserved to access static members outside of a class.
Then I was surprised when I realized that the following set_2() method was working as one could expect:
#include <iostream>
struct A {
int x;
// The two following methods seem to act similarly:
void set_1(int x) { this->x = x; }
void set_2(int x) { A::x = x; }
};
int main ()
{
A a;
a.set_1(13);
std::cout << a.x << std::endl;
a.set_2(17);
std::cout << a.x << std::endl;
return 0;
}
Output:
13
17
Is is a good and valid practice to use the scope operator (A::x) in this case? I would personnally prefer it, instead of using the this->x syntax.
Using A::x in this case is valid, but I think this->x is more idiomatic and less error-prone (the reader of the code can immediately see that x is a member of the class, without thinking what A is).
According to the C++ Standard (3.3.7 Class scope)
2 The name of a class member shall only be used as follows:
— in the scope of its class (as described above) or a class derived
(Clause 10) from its class,
— after the . operator applied to an expression of the type of its
class (5.2.5) or a class derived from its class,
— after the -> operator applied to a pointer to an object of its class
(5.2.5) or a class derived from its class,
— after the :: scope resolution operator (5.1) applied to the name of
its class or a class derived from its class.
For example data members of methods of a derived class can hide data members and/or methods of its base class. To access data members and nethods of the base class you can use the scope resolution operator.
struct Base
{
virtual ~Base() {};
virtual void Hello() const { std::cout << "Base" << std::endl; }
};
struct Derived : Base
{
virtual void Hello() const
{
Base::Hello();
std::cout << "and Derived" << std::endl;
}
};
Derived d;
d.Hello();
The A::x, in your case, still refers to your regular member variable; it just explicitly specifies which x you mean. Consider a class that derives from two other classes which have a member of the same name (not that that's very good coding style):
struct A { int x; };
struct B { int x; };
struct C : A, B
{
int foo() const
{
// return x; // ambiguous: which x do you mean?
return A::x; // unambiguous
}
};
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();
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();
}
I realy don't understand why it works, but below code shows an example of calling private method from the world without any friend classes:
class A
{
public:
virtual void someMethod(){
std::cout << "A::someMethod";
}
};
class B : public A
{
private:
virtual void someMethod(){
std::cout << "B::someMethod";
}
};
int main(){
A* a = new B;
a->someMethod();
}
outputs:
B::someMethod
Doesn't it violates encapsulation rules in C++? For me this is insane. The inheritance is public, but the access modifier in derived class is changed to private, thus the someMethod() in class B is private. So in fact, doing a->someMethod(), we are directly calling a private method from the world.
Consider the following code, a modification of the code in the original question:
class A
{
public:
virtual void X(){
std::cout << "A::someMethod";
}
};
class B : public A
{
private:
virtual void Y(){
std::cout << "B::someMethod";
}
};
int main(){
A* a = new B;
a->X();
}
It's easy to understand that it's legit to call X(). B inherits it from A as a public member. Theoretically if X() would call Y() this would be legit as well of course, although this is not possible because X() is declared in A which doesn't know Y(). But actually this is the case if X = Y, i.e. if both methods have the same name.
You may think of it as "B inherits a public method from A, that calls a private method (of B) with the same name".
a is a pointer to an A object where the method is public, so this is not a violation. Since, you have used virtual, the VTABLE is taken into account and you get the output as B::someMethod.
For me this is quite simple.
As you are allowed to asign any dynamic type inheritance of a class to an object of the parrent-class it would be vise versa.But as you are assigning the Child to its parrent object pointer this could be bad as if the class of B where bigger as A.
If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:
the dynamic type of the object,
a cv-qualified version of the dynamic type of the object,
a type that is the signed or unsigned type corresponding to the dynamic type of the object,
a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union),
a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
a char or unsigned char type.
So as in your code you aren't fitting this conditions, but as B has the sime size as A, it would be possible to run it. But it is undefined behavior.
And as you creat a new B the memory block a is pointing to has the method of printing B and not A.
The access control specifiers (public, protected and private) do not apply to member functions or data members. They apply to member function and data member names. And that works. If you can refer to the member without the name, you can access it.
That's precisely what's happening here. You're calling B::someMethod, but you're calling it using the name A::someMethod, which is public. No problem.
You're suggesting a private member function shouldn't be callable from outside of the class (disregarding friends for the moment). How would your desired semantics work in the following case?
Shared library hider:
hider.h:
typedef void (*FuncType)();
class Hider {
private:
static void privFunc();
public:
static void pubFunc();
FuncType getFunction() const;
};
hider.cpp
#include <cstdlib>
#include <iostream>
#include "hider.h"
void Hider::privFunc() {
std::cout << "Private\n";
}
void Hider::pubFunc() {
std::cout << "Public\n";
}
FuncType Hider::getFunction() const {
if (std::rand() % 2) {
return &pubFunc;
} else {
return &privFunc;
}
}
Application using library hider
#include "hider.hpp"
int main()
{
Hider h;
FuncType f = h.getFunc();
f();
}
What about the call to f()? Should it fail at runtime 50% of the time with some form of access control violation?
As suggested by DyP in the comments, a more realistic scenario is the well-known "template method" design pattern:
class Container
{
public:
void insert(const Item &item) {
preInsert();
data.insert(item);
postInsert();
}
private:
std::vector<Item> data;
virtual void preInsert() = 0;
virtual void postInsert() = 0;
};
class ThreadSafeContainer : public Container
{
private:
std::mutex m;
virtual void preInsert() {
m.lock();
}
virtual void postInsert() {
m.unlock();
}
};
Your semantics would mean this code wouldn't compile.
The following code does not compile in gcc:
namespace One{
class A{
};
};
namespace Two{
class A{
public:
void what(){
cout << "Two::A says what!" << endl;
}
};
class B : public One::A{
public:
B(){
A xx;
xx.what();
}
};
};
And it gives:
gccbug.cpp: In constructor ‘Two::B::B()’:
gccbug.cpp:23: error: ‘class One::A’ has no member named ‘what’
Now, I was told that this is correct behavior (due to injected base name of One::A making A refer to One::A). However, this code compiles in C# (well, after changing a few things), so this seems to be c++ specific.
What I'm wondering is.. why? Is there a specific purpose for injecting the base name "One::A" as "A"?
The only reason I can think of is that in C++ you are likely to refer to the base class name in the initializer list of the constructor, like this:
namespace Two {
/*...*/
class B : public One::A {
public:
B():A()
{
/*...*/
}
};
}
Of course the purpose then is different from the one in your example, because you actually declare a local variable inside the constructor, whereas in my example, the A() refers to the object of type A that is implicit in the definition of class B due to inheritance.
However, the situation of my example is more likely to occur, so I guess they thought let's not require the namespace to be made explicit in this case. As a consequence, any reference to A without a namespace is interpreted as referring to the base class, rather than any other class named A, even if it is in the same namespace as the declaration of B.
Is there a specific purpose for injecting the base name "One::A" as "A"?
Yes. It is so that you could write this:
namespace N
{
class A
{
A *a;
};
}
In the absence of injected-name, you've to write N::A *a which is not nice.
Note that it is because of injected-name, the following lines are allowed:
A::A *a1; //ok
A::A::A *a2; //ok
A::A::A::A *a3; //ok
A::A::A::A::A *a4; //ok
//and so on
Online demo
By qualifying A with One:: you added the A from namespace one in scope, so the compiler will look there for it's name resolution.