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
}
};
Related
Consider the following example:
class A { int x; };
Now what is A::x?
It cannot be an lvalue because it does not refer to a storage Location.
It cannot be a type, because the type would be decltype(A::x).
It is, in fact, an lvalue. [expr.prim.id.qual]/2:
A nested-name-specifier that denotes a class [...] followed by the
name of a member of either that class ([class.mem]) or one of its base
classes, is a qualified-id [...]. The result is the member. The type
of the result is the type of the member. The result is an lvalue if
the member is a static member function or a data member and a prvalue
otherwise.
Though its usage outside a class member access expression is severely restricted by [expr.prim.id]/2, it can notably be used in unevaluated operands, where its lvalueness can manifest:
struct A {
int x;
};
void f(int &);
using p = decltype(&(A::x)); // p is int*; the parens prevents forming a pointer-to-member
using q = decltype(f(A::x)); // q is void
A::x is merely a less ambiguous way of referring to the member x which can be necessary if the local context shadows that member:
Example 1:
A child class also has a member x.
struct B : public A
{
int x;
void foo()
{
int local_x = x;
int parent_x = A::x;
}
}
which would compile had you made x protected in class A (it's currently private).
Example 2:
You can even use it in a member function of A that has x as a parameter:
class A {
int x;
void foo(int x)
{
int parameter_x = x;
int member_x = A::x;
}
};
In addition to Bathsheba's answer, which is correct when you're within the class's scope, A::x can also be used as part of a pointer-to-member expression, i.e. &A::x, which returns a int A::*.
In this case, the standalone A::x is not valid and therefore the question of what it returns is moot.
From the C++ Standard (5.1 Primary expressions)
9 A nested-name-specifier that denotes a class, optionally followed by
the keyword template (14.2), and then followed by the name of a member
of either that class (9.2) or one of its base classes (Clause 10), is
a qualified-id; 3.4.3.1 describes name lookup for class members that
appear in qualified-ids. The result is the member. The type of the
result is the type of the member. The result is an lvalue if the
member is a static member function or a data member and a prvalue
otherwise. [ Note: a class member can be referred to using a
qualified-id at any point in its potential scope (3.3.7). —end note
]...
The qualified name allows to specify an otherwise hidden name for example when derived and base classes have members with the same name. For example
#include <iostream>
struct A
{
int i;
};
struct B : A
{
B( int i ) : A { i }, i( 2 * A::i ) {}
int i;
std::ostream &out( std::ostream &os = std::cout ) const
{
return os << "A::i = " << A::i << ", B::i = " << B::i;
}
};
int main()
{
B( 10 ).out() << std::endl;
return 0;
}
The program output is
A::i = 10, B::i = 20
Also (5.1 Primary expressions)
13 An id-expression that denotes a non-static data member or
non-static member function of a class can only be used:
(13.1) — as part of a class member access (5.2.5) in which the object
expression refers to the member’s class63 or a class derived from that
class, or
(13.2) — to form a pointer to member (5.3.1), or
(13.3) — if that id-expression denotes a non-static data member and it
appears in an unevaluated operand.
A::x is exact equivalent of accessing static variable in JAVA.
Regarding your example:-
1) x will be variable for distinct objects
2) A::x will be the variable for the class itself. Regardless of how many objects of A has been declared for every object the value of A::x will be same until assignment.
For example:-
#include<iostream>
using namespace std;
class A {
public:
static int x;
};
int A::x;
int main()
{
A a,b;
a.x=8;
b.x=6;
A::x=10;
return 0;
}
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;
}
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.
It seems that a protected member from a template policy class is inaccessible, even with a class hierarchy which seems correct.
For instance, with the following code snippet :
#include <iostream>
using namespace std;
template <class T>
class A {
protected:
T value;
T getValue() { return value; }
public:
A(T value) { this->value = value; }
};
template <class T, template <class U> class A>
class B : protected A<T> {
public:
B() : A<T>(0) { /* Fake value */ }
void print(A<T>& input) {
cout << input.getValue() << endl;
}
};
int main(int argc, char *argv[]) {
B<int, A> b;
A<int> a(42);
b.print(a);
}
The compiler (clang on OS X, but gcc returns the same type of error) returns the following error :
Untitled.cpp:18:21: error: 'getValue' is a protected member of 'A<int>'
cout << input.getValue() << endl;
^
Untitled.cpp:25:5: note: in instantiation of member function 'B<int, A>::print' requested here
b.print(a);
^
Untitled.cpp:8:7: note: can only access this member on an object of type 'B<int, A>'
T getValue() { return value; }
^
1 error generated.
The strange thing is that the last note from the compiler is totally correct but already applied since the b object is of type 'B<int, A>'. Is that a compiler bug or is there a problem in the code ?
Thanks
You have misunderstood the meaning of protected access.
Protected members are callable by derived classes. But only on the base object contained inside the class itself.
For example, if i simplify the problem, using :
class A {
protected:
void getValue(){}
};
class B : protected A
{
public:
void print(A& input)
{
input.getValue(); //Invallid
}
};
getValue cannot be called on a "A" object other than the "A" object inside the class itself.
This for example is valid.
void print()
{
getValue(); //Valid, calling the base class getValue()
}
As pointed out by Dan Nissenbaum and shakurov. This is however also valid:
void print(B& input)
{
input.getValue();
}
This is because we explicitly say that input is a object of B. And the compiler know that all that objects of B has protected access to getValue. In the case when we pass a A&, the object might as-well be a type of C, wich could be derrived from A with private access.
Let's forget for a minute about the template and look at this:
class A {
protected:
int value;
int getValue() { return value; }
public:
A(int value) { this->value = value; }
};
class B : protected A {
public:
B() : A(0) { /* Fake value */ }
void print(A& input) {
cout << input.getValue() << endl;
}
};
The print() method's implementation is wrong because you can't access non-public member of A inside B. And here's why: from within B, you can only access non-public members of B. Those members may be either inherited or not — it doesn't matter.
On the other hand, A& input may not be a reference to an instance of B. It may be a reference to another subclass (which may well have getValue() inaccessible).
Member functions of a derived class have access to protected base class members within any object of its type that is passed as an argument so long as the explicitly declared class of the object passed as an argument is that of the the derived class (or a further derived class).
Objects explicitly passed as the base class type cannot have their protected members accessed within the derived class's member functions.
In other words, if we have:
class A
{
protected:
int x;
}
class B : public A
{
void foo(B b)
{
b.x; // allowed because 'b' is explicitly declared as an object of class B
}
void goo(A a)
{
a.x; // error because 'a' is explicitly declared as having *base* class type
}
};
...then the line a.x is not allowed because the explicit type of the argument is A, but the rule for protected access only applies to objects explicitly defined as the same class as the class attempting to access the member. (...Or a class derived from it; i.e., if class Cderives from B, then passing an object explicitly declared as an object of class C will also have x accessible within B member functions.)
The reason for this is given by shakurov when he writes (paraphrasing)
A& input might not be a reference to an instance of B. It may be a
reference to another subclass (which may well have getValue()
inaccessible)
An excellent explication of this answer is also given here: accessing a protected member of a base class in another subclass.
As a matter of interest, I believe that this comes from the C++ standard here:
11.4 Protected member access [class.protected] 1 An additional access check beyond those described earlier in Clause 11 is applied when a
non-static data member or non-static member function is a protected
member of its naming class (11.2)115 As described earlier, access to a
protected member is granted because the reference occurs in a friend
or member of some class C. If the access is to form a pointer to
member (5.3.1), the nested-name-specifier shall denote C or a class
derived from C. All other accesses involve a (possibly implicit)
object expression (5.2.5). In this case, the class of the object
expression shall be C or a class derived from C.
Don't get distracted by the template. It has nothing to do with the error. The line in main that the compiler is complaining about creates an object of type B<int, a> and tries to access a protected member. That's not legal, regardless of the type. You can only use protected members from inside a member function or friend function. For example:
struct S {
protected:
void f();
};
int main() {
S s;
s.f(); // error: attempts to call a protected member function
}
Must I need to redefine all the overloading operators with derived type if I require to use them in derived class?
The following code compiles fine:
class Point {
public:
Point(int X = 0, int Y = 0):x(X), y(Y) {}
virtual ~Point() {}
Point operator +(Point &rhs) {
return Point(x + rhs.x, y + rhs.y);
}
protected:
int x, y;
};
class Vector : public Point {
public:
Vector(int X, int Y) : Point(X, Y) {}
~Vector() {}
Vector operator +(Vector &rhs) {
return Vector(x + rhs.x, y + rhs.y);
}
};
int main()
{
Vector v1(1, 2);
Vector v2(3, 2);
Vector v3 = v2 + v1;
}
But from what I've read,
C++ Primer 4th Ed. Section 15.5.3.
If a derived class wants to make all the overloaded versions available through its type, then it must either redefine all of them or none of them.
Does the part of the quote "none of them" make any sense here?
What it means is that if Point had more than one operator+(), and you only redefined one of them, then only that one would be accessible in the derived class; the other overloads would be hidden. If you declare no operator+() in the derived class, then all of the parent ones are available; if you declare any in the derived class, then none of the parent ones are available.
Make sense? This case is fine: the parent declares one, and you redefine that one. No problems. If the parent declared two, though, then your child class, which only declares one, would only have access to that one.
Overloading operators in derived class from IBM.
A member function named f in a class A
will hide all other members named f in
the base classes of A, regardless of
return types or arguments. The
following example demonstrates this:
struct A {
void f() { }
};
struct B : A {
void f(int) { }
};
int main() {
B obj_B;
obj_B.f(3);
// obj_B.f();
}
The compiler would not allow the
function call obj_B.f() because the
declaration of void B::f(int) has
hidden A::f().
To overload, rather than hide, a
function of a base class A in a
derived class B, you introduce the
name of the function into the scope of
B with a using declaration. The
following example is the same as the
previous example except for the using
declaration using A::f:
struct A {
void f() { }
};
struct B : A {
using A::f;
void f(int) { }
};
int main() {
B obj_B;
obj_B.f(3);
obj_B.f();
}
So if you do not overload all of them, then only the overloaded functions will be used.
In C++, there is no overloading across scopes derived class scopes are not an exception to this general rule.
There is no overload resolution between Derived and Base class. An example:
class B
{
public:
int func1(int i)
{
cout<<"B::func1()";
return i+1;
}
};
class D : public B
{
public:
double func1(double d)
{
cout<<"D::func1()";
return d+1.3;
}
};
int main ()
{
D *pd = new D;
cout << pd->func1(2) <<endl;
cout << pd->func1(2.3)<<endl;
return 0;
}
The output is:
D::func1()3.3
D::func1()3.6
This same rule applies for operator member functions as well, after all they are member functions too!
So in your code example if Point had more than one operator+(), and you redefined the same operator in Derived class then only that derived class operator will be accessible to objects of derived class because that version of the function hides the other Base class versions of operator+().
If you do not redefine the operator+() in the derived class, then none of the parent class versions of the operator+() are hidden and hence accessible through objects of Derived class.
Hence the statement:
If a derived class wants to make all the overloaded versions available through its type, then it must either redefine all of them or none of them.
Also, please note that overloading, overriding and function hiding are three terms that are loosely mis-used interchangeably sometimes but they all have separate meanings.