I have always been under the impression that <class>::<variable> is for accessing static members. However, I am surprised to find out that the following compiles just fine. (I would have used this-> as shown in the inline comment.)
Further investigation on Google/StackOverflow doesn't show anything pertinent to this behavior, I wonder if anyone could shed some light on this.
class Test {
private:
int x;
public:
void set_x(int x) {
// this->x = x;
Test::x = x;
}
};
int main(int argc, char *argv[])
{
return 0;
}
ENV: clang version 7.0.0- (trunk)
The :: is the scope-resolution operator and can be use to specify which of a number of symbols of the same name but different but visible scope the reference refers to.
Either scope-resolution or this-> may be used in this example, but scope-resolution itself has more general applicability within the language.
http://eel.is/c++draft/basic.lookup.qual#class.qual
If the nested-name-specifier of a qualified-id nominates a class, the name
specified after the nested-name-specifier is looked up in the scope of the
class ([class.member.lookup]), except for the cases listed below. The name
shall represent one or more members of that class or of one of its base
classes ([class.derived]). [ Note: A class member can be referred to using a
qualified-id at any point in its potential scope ([basic.scope.class]). — end
note ]
Yes, it merely specifies the class name/namespace the object was declared in. There can be more contrived cases, like this one:
struct Base {
virtual int answer() const { return 42; }
};
struct Left: public virtual Base {
virtual int answer() const { return 314; } // raise the heat
};
struct Right: public virtual Base {
virtual int answer() const { return -42; } // to the other side
};
struct Bottom: Left, Right {
virtual int answer() const { return Base::answer(); } // back to basics
};
#include <iostream>
int main() {
Bottom b;
std::cout << b.answer() << std::endl; // 42
std::cout << b.Right::answer() << std::endl; // -42
std::cout << b.Left::answer() << std::endl; // 314
std::cout << b.Base::answer() << std::endl; // again, 42
}
The thing with static members, you cannot access them other way (and they cannot be virtual, btw.) (Still, if class Child derives Base and both define a static member staticMember, you should use qualified forms — either Base::staticMember or Child::staticMember — to disambiguate between the two; unqualified version refers to Child's one in this case.)
But non-static methods have an object context inside them, so members can be used unqualified — still they can be used other way, too.
P.S. Where did that this-> originate from? I sometimes see it every here and there, still nobody has been able to explain why.
There are several reasons to qualify with class name an instance variable (or member function). This list is not exhaustive, and only mentions cases where we would use it on object instances, not types:
Inside a member function, if derived and parent have the same member name, the derived name hides the base. Qualification can allow access to the base. This applies to both variables and member functions.
If inside a member function in hierarchy with multiple inheritance, it can select between which parent you want to use.
It can be used to bypass the virtual function dispatch mechanism by calling the function implementation in the type specified, rather than in the most overriding type. Example: d.Base::foo();
It can be used to specify a member that was hidden by a local variable, similar to qualifying a member with this-> (Though I've never seen this done, and prefer this-> instead.)
It is frequently used in conjunction with a "using" declaration, to bring base class function names into the overload set of the derived class that adds some of its own with the same name. Without this, the base names would be hidden.
Related
In this thread the author of the accepted answer explains why the overridden method in the derived class can not be resolved by the compiler. However the example is relative to a type cast resolution, that is both the base and derived overloaded method have one parameter only and the ambiguity is limited to that parameter type.
But where is the ambiguity when the overloaded methods have a different number of parameters, like in this example?
Note that I'm not asking why the example produces a compile error, I'm asking why the language was designed this way.
#include <iostream>
using namespace std;
class A
{
public:
inline int f(int x) { return x; }
};
class B: public A
{
public:
inline int f(int x, int y) { return x+y; }
};
int main()
{
B b;
cout << b.f(1) << endl; // COMPILE ERROR
cout << b.f(1,2) << endl;
}
The reason you get a compiler error is that f from class A is hidden by the f in class B.
When the compiler does member name lookup, it uses base classes only if the name is not found in the object's class, so it doesn't matter if you have a member in a base class that has a proper parameter list for your call.
From the standard:
10.2.5 Otherwise (i.e., C does not contain a declaration of f or the resulting declaration set is empty), S(f, C) is
initially empty. If C has base classes, calculate the lookup set for f in each direct base class subobject Bi
,
and merge each such lookup set S(f, Bi) in turn into S(f, C).
In C++, name lookup will stop looking for other names as soon as it find the requested name in one of the base classes.
In your case, the name f is defined in B, so the compiler stop looking in the other base classes.
You can make A::f visible with a using declaration :
class B: public A
{
public:
using A::f;
int f(int x, int y) { return x+y; }
};
The compiler will look for the implementation of function f in class B. The compiler found such an implementation, which has two arguments. You provided only one argument, so there is your error.
How would you take away overloads that make no sense in a derived class? Even in your example, assume that if you have a B instance, you wanted to forbid the use of the single-parameter function. As it is written now, you've removed the single-parameter version (well, at least removed it from name resolution in the context of a B instance). But if you wanted to still have that version available, you can specify using A::F; in your class to bring in the single-parameter version.
I think i'm aware of accessibilty but I'm not sure if I understand visibility very clearly
For example:
class X
{
int x;
};
Here, 'x' is only visible in class and but accessible outside of class. If I'm correct, Can someone explain the text in that answer about how visibility is not controlled etc..?
(C++03/11.0) It should be noted that it is access to members and base classes that
is controlled, not their visibility. Names of members are still
visible, and implicit conversions to base classes are still
considered, when those members and base classes are inaccessible. The
interpretation of a given construct is established without regard to
access control. If the interpretation established makes use of
inaccessible member names or base classes, the construct is
ill-formed.
Perhaps this example helps:
class Bob
{
private:
int foo(int, int);
};
class David : Bob
{
void goo() {
int a = foo(1, 2); // #1
}
};
class Dani : Bob
{
void foo();
void goo() {
int a = foo(1, 2); // #2
}
};
On line #1, the name foo is visible, but the function which it names is not accessible (on account of being private to Bob). This is a compilation error, but the compiler knows that there is a potential function Bob::foo that would match, but isn't accessible.
On line #2, the name foo only refers to Dani::foo, while Bob::foo is not visible (because it is hidden), and so there is simply no matching function for the call foo(1, 2). This is also a compilation error, but this time the error is that there is no matching function at all for the call.
C++ has some esoteric feature concerning private class member names visibility and accessibility. By definition, a private class member name is only accessible by the class members and friends. However the rule of visibility can confuse many. They can be summarized as follows.
A private member's name is only accessible to other members and friends.
A private member is visible to all code that sees the class's definition. This means that its parameter types must be declared even if they can never be needed in this translation unit...
Overload resolution happens before accessibility checking.
In C++ today ("C++03" and earlier variants), the notions of accessibility and visibility are
independent. Members of classes and namespaces are visible whenever they are "in
scope" and there is no mechanism to reduce this visibility from the point of declaration.
Accessibility is only a parameter for class members and is orthogonal to the notion of
visibility. This latter observation is frequently surprising to novice C++ programmers. See this PDF.
Consider the following example.
#include < complex>
class Calc
{
public:
double Twice( double d );
private:
int Twice( int i );
std::complex Twice( std::complex c );
};
int main()
{
Calc c;
return c.Twice( 21 ); // error, Twice is inaccessible
}
When the compiler has to resolve the call to a function, it does three main things, in order:
Before doing anything else, the compiler searches for a scope that
has at least one entity named Twice and makes a list of candidates.
In this case, name lookup first looks in the scope of Calc to see if
there is at least one function named Twice; if there isn't, base
classes and enclosing namespaces will be considered in turn, one at a
time, until a scope having at least one candidate is found. In this
case, though, the very first scope the compiler looks in already has
an entity named Twice — in fact, it has three of them, and so that
trio becomes the set of candidates. (For more information about name
lookup in C++, with discussion about how it affects the way you
should package your classes and their interfaces
Next, the compiler performs overload resolution to pick the unique
best match out of the list of candidates. In this case, the argument
is 21, which is an int, and the available overloads take a double, an
int, and a complex. Clearly the int parameter is the best match for
the int argument (it's an exact match and no conversions are
required), and so Twice(int) is selected.
Finally, the compiler performs accessibility checking to determine
whether the selected function can be called.
Note that accessibility (defined by modifiers in C++) and visibility are independent. Visibility is based on the scoping rules of C++. A class member can be visible and inaccessible at the same time.
Static members as an example are visible globally through out the running of your application but accessible only with regard to the modifier applied to them.
As a note: when you declare a class, the scope is private by default (opposed to a struct where members are public by default.)
The variable member 'x' is only accessible by your class and its friends. No one else can ever access 'x' directly (it can indirectly if you have a function returning a reference to it, which is a really bad idea.)
The text you quoted talks about visibility to the compiler, so X::x exists, no matter what. It won't disappear just because it's private. The visibility is used to find the member you are referencing and the first that matches is returned. At that point the compiler checks the accessibility, if accessible, you're all good. If not it is ill-formed.
Note that I mentioned friends. That keyword makes all variable members accessible. When the compiler deals with a friends, it completely ignores all the protected and private keywords.
In most cases, that's a very easy process. It goes in order. Period.
Where it becomes more complicated is when you start using virtual functions: these can be made public, protected, and private and that can change depending on the class declaration... (A derives from B and makes a protected virtual function public; it's generally not a good idea, but C++ doesn't prevent you from doing so.) Of course this only applies to functions, not variable members, so that's a different subject.
That accessability and visibility are independet confuses especially in such situations:
class A
{
public:
void Foo(int i){
}
};
class B : public A
{
private:
void Foo(){
}
};
int main(){
B b{};
b.Foo(12);
}
Programmers from other languages would expect that A::Foo(int) would be callable because it is public. The point here is, that the private B::Foo hides the inherited proc.
This can be solved with a using declaration using A::Foo. But it becomes really hard in this sitation:
class A
{
public:
void Foo(int i){
}
};
class B : public A
{
public:
using A::Foo;
private:
void Foo(){
}
};
class C : public B
{
public:
using B::Foo;
private:
void Foo(char c){
}
}
int main(){
B b{};
b.Foo(12);
}
Using requires that there is NO private function. AFAIK the best way to solve it is to use some prefixes / suffixes for private or protected functions (like do_XXX() or do_XXX_internal).
In the STL private members are usually prefixed by a single underscore (these are reserved identifiers).
I might be very well just tired or too long far from C++ but this one really surprised me today:
#include <iostream>
class Interface
{
public:
virtual int aa() const = 0;
virtual int bb() const = 0;
};
class Usage : public Interface
{
private:
virtual int aa() const
{
int a = 10 * 10;
return a;
}
virtual int bb() const
{
int b = 20 * 20;
return b;
}
};
int main(int argc, char* argv[])
{
Interface* i = new Usage();
std::cout << i->bb() << std::endl;
return 0;
}
I'd expect compiler and/or linker would complain about either bad function signature or at least about missing implementation. Considering this is working and ok, what is the meaning of public/protected/private modifiers when it's hidden by the top class declaration?
How does this rule call in C++ ?
This is specified in paragraph 11.6.1 of the standard:
The access rules (clause 11) for a
virtual function are determined by its
declaration and are not affected by
the rules for a function that later
overrides it. [Example - basically same as yours]
Access is checked at the call point
using the type of the expression used
to denote the object for which the
member function is called . The access
of the member function in the class in
which it was defined is in general not
known.
Interface* i = new Usage();
std::cout << i->bb() << std::endl;
This is working because the function name is resolved based on the static type of the object.
Here the object is i whose static type is Interface* which has a public function name bb(). Hence, the compiler doesn't see any problem, as the requirement to call a member function meets it.
Also note that accessibilities (public, private and protected) are compile-time constructs. At runtime, there is no such thing. Compiler can detect any violation of rules related to accessibility at compile time only. It cannot know what happens at runtime.
So even if i points to an object whose type is Usage which has defined bb() in the private section, the compiler is fine with it, as noted before the static type of i is still Interface* which has a public function bb(). The compiler doens't bother with the dynamic type of object and how it overrides the function, because it cannot, precisely for the reason that its dynamic; its determined at runtime.
private means you can't inherit from it. protected or public you can inherit from but there is nothing stopping you limiting the visibility to a lower level (i.e. public to protected or private; or protected to private) in your top class.
I would like to implement interactions between two objects whose types are derived from a common base class. There is a default interaction and specific things may happen once objects of the same type interact.
This is implemented using the following double dispatch scheme:
#include <iostream>
class A
{
public:
virtual void PostCompose(A* other)
{
other->PreCompose(this);
}
virtual void PreCompose(A* other)
{
std::cout << "Precomposing with an A object" << std::endl;
}
};
class B : public A
{
public:
virtual void PostCompose(A* other) // This one needs to be present to prevent a warning
{
other->PreCompose(this);
}
virtual void PreCompose(A* other) // This one needs to be present to prevent an error
{
std::cout << "Precomposing with an A object" << std::endl;
}
virtual void PostCompose(B* other)
{
other->PreCompose(this);
}
virtual void PreCompose(B* other)
{
std::cout << "Precomposing with a B object" << std::endl;
}
};
int main()
{
A a;
B b;
a.PostCompose(&a); // -> "Precomposing with an A object"
a.PostCompose(&b); // -> "Precomposing with an A object"
b.PostCompose(&a); // -> "Precomposing with an A object"
b.PostCompose(&b); // -> "Precomposing with a B object"
}
I have two, unfortunately quite different questions regarding this code:
Do you think this is a reasonable approach? Would you suggest something different?
If I omit the first two B methods, I get compiler warnings and errors that the last two B methods hide the A methods. Why is that? An A* pointer should not be cast to a B* pointer, or should it?
Update: I just found out that adding
using A::PreCompose;
using A::PostCompose;
makes the errors and warnings vanish, but why is this necessary?
Update 2: This is neatly explained here: http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9, thank you. What about my first question? Any comments on this approach?
Double dispatch is usually implemented differently in C++, with the base class having all different versions (which makes it a maintenance nightmare, but that is how the language is). The problem with your attempt to double dispatch is that dynamic dispatch will find the most derived type B of the object on which you are calling the method, but then the argument has static type A*. Since A does not have an overload that takes B* as argument, then the call other->PreCompose(this) will implicitly upcast this to A* and you are left with single dispatch on the second argument.
As of the actual question: why is the compiler producing the warnings? why do I need to add the using A::Precompose directives?
The reason for that are the lookup rules in C++. Then the compiler encounters a call to obj.member(), it has to lookup the identifier member, and it will do so starting from the static type of obj, if it fails to locate member in that context it will move up in the hierarchy and lookup in the bases of the static type of obj.
Once the first identifier is found, lookup will stop and try to match the function call with the available overloads, and if the call cannot be matched it will trigger an error. The important bit here is that lookup will not look further up in the hierarchy if the function call cannot be matched. By adding the using base::member declaration, you are bringing the identifier member from the base class into the current scope.
Example:
struct base {
void foo( const char * ) {}
void foo( int ) {}
};
struct derived : base {
void foo( std::string const & ) {};
};
int main() {
derived d;
d.foo( "Hi" );
d.foo( 5 );
base &b = d;
b.foo( "you" );
b.foo( 5 );
d.base::foo( "there" );
}
When the compiler encounters the expression d.foo( "Hi" ); the static type of the object is derived, and lookup will check all member functions in derived, the identifier foo is located there, and lookup does not proceed upwards. The argument to the only available overload is std::string const&, and the compiler will add an implicit conversion, so even if there could be a best potential match (base::foo(const char*) is a better match than derived::foo(std::string const&) for that call) it will effectively call:
d.derived::foo( std::string("Hi") );
The next expression d.foo( 5 ); is processed similarly, lookup starts in derived and it finds that there is a member function there. But the argument 5 cannot be converted to std::string const & implicitly and the compiler will issue an error, even if there is a perfect match in base::foo(int). Note that this is an error in the call, not an error in the class definition.
When processing the third expression, b.foo( "you" ); the static type of the object is base (note that the actual object is derived, but the type of the reference is base&), so lookup will not search in derived but rather start in base. It finds two overloads, and one of them is a good match, so it will call base::foo( const char* ). The same goes for b.foo(5).
Finally, while adding the different overloads in the most derived class hide the overloads in the base, it does not remove them from the objects, so you can actually call the overload that you need by fully qualifying the call (which disables lookup and has the added side effect of skipping dynamic dispatch if the functions were virtual), so d.base::foo( "there" ) will not perform any lookup at all and just dispatch the call to base::foo( const char* ).
If you had added a using base::foo declaration to the derived class, you would add all the overloads of foo in base to the available overloads in derived, and the call d.foo( "Hi" ); would consider the overloads in base and find that the best overload is base::foo( const char* );, so it will actually be executed as d.base::foo( "Hi" );
In many cases, developers are not always thinking on how the lookup rules actually work, and it might be surprising that the call to d.foo( 5 ); fails without the using base::foo declaration, or worse, that the call to d.foo( "Hi" ); is dispatched to derived::foo( std::string const & ) when it is clearly a worse overload than base::foo( const char* ). That is one of the reasons why compilers warn when you hide member functions. The other good reason for that warning is that in many cases when you actually intended to override a virtual function you might end up mistakenly changing the signature:
struct base {
virtual std::string name() const {
return "base";
};
};
struct derived : base {
virtual std::string name() { // missing const!!!!
return "derived";
}
}
int main() {
derived d;
base & b = d;
std::cout << b.name() << std::endl; // "base" ????
}
A small mistake while trying to override the member function name (forgetting the const qualifier) means that you are actually creating a different function signature. derived::name is not an override to base::name and thus a call to name through a reference to base will not be dispatched to derived::name!!!
using A::PreCompose;
using A::PostCompose;
makes the errors and warnings vanish, but why is this necessary?
If you add new functions to your derived class with same name as your base class contains and if you don't override the virtual functions from base class, then new names hide the old names from the base class.
That is why you need to unhide them by explicity writing:
using A::PreCompose;
using A::PostCompose;
Other way to unhide them (in this particular case) is , override the virtual functions from base class which you've done in the code you've posted. I believe that code would compile just fine.
Classes are scopes and the look up in a base class is described as looking up in an enclosing scope.
When looking up overload of a function, looking up in enclosing scope is not done if a function was found in the nested one.
A consequence of the two rules is the behaviour you experimented. Adding the using clauses import the definition from the enclosing scope and is the normal solution.
I see some usage of internal struct in c++ function.
There is a common interface IBase. Here is the draft code.
class IBase
{
virtual Method()=0;
}
vector<IBase*> baseList;
Then a function defined an internal class based on that IBase, and then push the internal class object into the baseList.
void func()
{
struct Object : public IBase
{
virtual Method()
{
// Method of Object in func
}
}
IBase* base = new Object();
baseList->push(base);
}
It seems a strange usage, but a nice implementation of message/event creation pattern.
Other threads maybe use this baseList to handle the incoming event.
What's the scope of internal struct of "struct Object"? It's very interesting. Is there some documents talking about this?
What's the scope of internal struct of "struct Object"?
The scope of the local classes is the function in which they're defined.But that isn't interesting in itself.
What makes local classes interesting is that if they implement some interface (like your code does), then you can create instances of it (using new) and return them (for example, as std::vector<IBase*>), thereby making the implementation accessible through the base class pointer even outside the function.
Some other facts about local classes:
They cannot define static member variables.
They cannot access nonstatic "automatic" local variables of the enclosing function. But they can access the static variables.
They can be used in template functions.
If they are defined inside a template function, then they can use the template parameters of the enclosing function.
Local classes are final, that means users outside the function cannot derive from local class to function. Without local classes, you'd have to add an unnamed namespace in separate translation unit.
Local classes are used to create trampoline functions usually known as thunks.
EDIT
Some references from the Standard (2003)
9.8 Local class declarations [class.local]
\1. A class can be defined within a function definition; such a class is
called a local class. The name of a
local class is local to its enclosing
scope. The local class is in the scope
of the enclosing scope, and has the
same access to names outside the
function as does the enclosing
function. Declarations in a local
class can use only type names, static
variables, extern variables and
functions, and enumerators from the
enclosing scope.
[Example:
int x;
void f()
{
static int s ;
int x;
extern int g();
struct local {
int g() { return x; } // error: x is auto
int h() { return s; } // OK
int k() { return ::x; } // OK
int l() { return g(); } // OK
};
// ...
}
local* p = 0; // error: local not in scope
—end example]
\2. An enclosing function has no special access to members of the local
class; it obeys the usual access rules
(clause 11). Member functions of a
local class shall be defined within
their class definition, if they are
defined at all.
\3. If class X is a local class a nested class Y may be declared in
class X and later defined in the
definition of class X or be later
defined in the same scope as the
definition of class X. A class nested
within a local class is a local class.
\4. A local class shall not have static data members.
\4. A local class shall not have static data members.
BUT you can do this, inside of a local class
int GetCount()
{
class _local
{
public:
static int Count(int count = std::numeric_limits<int>::max())
{
static int count_ = 0;
if (count != std::numeric_limits<int>::max()) count_ = count;
return count_;
}
static float Operation(float a, float b)
{
_local::Count(_local::Count() + 1);
return a;
}
};
_local::Count(0);
CALLBACK( _local::Operation);
return _local::Count();
}
_local::Count can be used to read and write the otherwise static variable
-aydin
This is normal C++. The scope of struct Object is only the function func. However, you can still use objects of this type without knowing which concrete type they are, since they inherit from IBase. This is used to encapsulate implementation.
A very interesting use of a local class is presented by Jason Turner in his CppCon talk focused on programming of Commodore 64 game in C++17. He shows how to use the RAII principle on the function level.
He basically establishes invariants in the constructor of a local class in a function returning an instance of this class. The invariants duration is thusly controlled by the lifetime of the returned object. It is quite similar to what RAII wrappers like std::lock do, just slightly different.
You can see the appropriate part here, but I love his performance and recommend to see it all the way through.