I was reading the C++0x FAQ by Stroustrup and got stuck with this code. Consider the following code
struct A
{
void f(double)
{
std::cout << "in double" << std::endl;
}
};
struct B : A
{
void f(int)
{
std::cout << "in int" << std::endl;
}
};
int main()
{
A a; a.f(10.10); // as expected, A.f will get called
B b; b.f(10.10); // This calls b.f and we lose the .10 here
return 0;
}
My understanding was when a type is inherited, all protected and public members will be accessible from the derived class. But according to this example, it looks like I am wrong. I was expecting the b.f will call base classes f. I got the expected result by changing the derived class like
struct B : A
{
using A::f;
void f(int)
{
std::cout << "in int" << std::endl;
}
};
Questions
Why was it not working in the first code?
Which section in the C++ standard describes all these scoping rules?
Its because A::f is "hidden" rather than "overloaded" or "overridden". Refer:
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9
The first code works as c++ is designed to work.
Overloading resolution follows a very complicated set of rules. From Stroustrup's c++ bible 15.2.2 "[A]mbiguities between functions from different base classes are not resolved based on argument types."
He goes on to explain the use of "using" as you have described.
This was a design decision in the language.
I tend to follow the Stroustrup book rather than the standard, but I'm sure it is in there.
[Edit]
Here it is (from the standard):
Chapter 13
When two or more different declarations are specified for a single name in the same scope, that name is said to be
overloaded.
And then:
13.2 Declaration matching
1 Two function declarations of the same name refer to the same function if they are in the same scope and have equivalent parameter declarations (13.1). A function member of a derived class is not in the same scope as a function member of
the same name in a base class.
Search for overload resolution. A similar, but not identical question.
In C++, there is no overloading across scopes, scoped in derived classes are not an exception.
(According to The C++ Programming Language)
For more info, check out http://www.research.att.com/~bs/bs_faq2.html#overloadderived
In the first case, the base class method 'f' is hidden by the derived class method. In C++ there is no overloading across scopes; that is why it is not called. The C++ standard explains all the member name lookup rules in the section 10.2 Member name lookup [class.member.lookup].
HTH
The first version of code should really call B::f. You re-define the symbol "f" in struct "B", so it hides the original symbol "f" from struct "A". It is not an overload, as it may seem.
Whenever compiler meets b.f(), it searches the "B" struct for a symbol "f". It is present there, so the compiler decides to call B::f(int), converting double to int. It sees no need to scan the parent class for a more suitable function...
Yet, when you add "using A::f", it is an explict directive for the compiler to scan a parent class for symbol "f". Now, B class has two overloaded functions: for int and for double.
I also believe, that you could write b.A::f() without using "using" directive in the original example...
Related
I have this code (diamond problem):
#include <iostream>
using namespace std;
struct Top
{
void print() { cout << "Top::print()" << endl; }
};
struct Right : Top
{
void print() { cout << "Right::print()" << endl; }
};
struct Left : Top
{
void print() { cout << "Left::print()" << endl; }
};
struct Bottom: Right, Left{};
int main()
{
Bottom b;
b.Right::Top::print();
}
I want to call print() in Top class.
When I try to compile it I get error: 'Top' is an ambiguous base of 'Bottom' on this line: b.Right::Top::print();
Why is it ambiguous? I explicitly specified that I want Top from Right and not from Left.
I don't want to know HOW to do it, yes it can be done with references, virtual inheritance, etc. I just want to know why is b.Right::Top::print(); ambiguous.
Why is it ambiguous? I explicitly specified that I want Top from Right and not from Left.
That was your intent, but that's not what actually happens. Right::Top::print() explicitly names the member function that you want to call, which is &Top::print. But it does not specify on which subobject of b we are calling that member function on. Your code is equivalent conceptually to:
auto print = &Bottom::Right::Top::print; // ok
(b.*print)(); // error
The part that selects print is unambiguous. It's the implicit conversion from b to Top that's ambiguous. You'd have to explicitly disambiguate which direction you're going in, by doing something like:
static_cast<Right&>(b).Top::print();
The scope resolution operator is left-associative (though it doesn't allow parentheses).
So whereas you want to refer to A::tell inside B, the id-expression refers to tell inside B::A, which is simply A, which is ambiguous.
The workaround is to first cast to the unambiguous base B, then cast again to A.
Language-lawyering:
[basic.lookup.qual]/1 says,
The name of a class or namespace member or enumerator can be referred to after the :: scope resolution operator applied to a nested-name-specifier that denotes its class, namespace, or enumeration.
The relevant grammar for nested-name-specifier is,
nested-name-specifier:
type-name ::
nested-name-specifier identifier ::
So, the first nested-name-specifier is B:: and A is looked up within it. Then B::A is a nested-name-specifier denoting A and tell is looked up within it.
Apparently MSVC accepts the example. Probably it has a nonstandard extension, to resolve ambiguity by backtracking through such specifiers.
Actually, giving code is working fine as I tried it on Visual Studio 2019.
There are two way to solve Diamond Problem;
- Using Scope resolution operator
- Inherit base class as virtual
Calling print function by b.Right::Top::print() should be executed with no errors. But there is still two objects of your base class (Top) referred from your Bottom class.
You can find additional detail in here
So as I understand it, when I see double colons(abc::xyz) used the thing on the left is a namespace and the thing on the right can be a function or variable of some sort that is defined in that namespace. ex. namespace::bar, namespace::foo()
Now, can the thing on the left be a class? ex. class::bar, class::foo()
If so, does anyone have any info on this. I can find lots of info of scope resolution pertaining to namespaces but not when it comes to classes.
In my situation I am going through a rather large project of code that is from another individual.
The code usage that I am trying to understand is that I have the following line of code...
multi_img::ptr input = imginput::ImgInput(config.input).execute();
On the right the imginput::ImgInput() can be found because there is a namespace imginput that I can find. But on the left, the multi_img::ptr, there is no multi_img namespace in the project. There is a multi_img class that contains the following line...
typedef boost::shared_ptr<multi_img> ptr;
I believe this is what multi_img::ptr means but can not find any documentation to back up my assumption.
Now, can the thing on the left be a class?
Yes it can, and to justify consider the following example:
#include <iostream>
class foo {
public:
void fun() const { std::cout << "foo:fun()" << std::endl; }
};
int main() {
foo f;
f.foo::fun();
return 0;
}
DEMO
Every class member lies in the scope of its class.
Edit after #Cheersandhth.-Alf constructive comment:
Thus, you can access a member through an object with either the classical way (e.g., f.fun()) in which case you'll have a virtual call or you call it like in the example (i.e., f.foo::fun()) in which case you explicitly disambiguate the scope of member function at compile time.
Yes, you can have a class name on the left of ::. It is used to denote a member of that class. The multi_img class has a member called ptr. As you have shown, that member is a typedef. That is, the type multi_img::ptr is a synonym of boost::shared_ptr<multi_img>.
Note that :: is used to access static members and nested types, since these only require the name of the class and not a particular object that of that class type. We use . and -> to access non-static data members of a particular object.
Usually the classname::member notation is used to
Access static members.
E.g. Blah::uuid.
Prevent virtual call.
E.g. in Blah::foo, a call like Base::foo().
Disambiguate.
E.g. with two bases A and B, both of which provides a foo, a call like B::foo().
Some older libraries use classes instead of namespaces. I vaguely recall an XML library and a GUI library. Not sure which.
Personally I do the class-as-faux-namespace for enumeration types, e.g.
struct Weekdays
: Non_instantiable
{
enum Enum { wednesday, friday, saturday };
};
used like
auto foo() -> Weekdays::Enum { return Weekdays::friday; }
even after C++11 started supported enum class.
Sometimed it is difficult to know whether the nested name specifier denotes a namespace or a class because the syntax is the same. Moreother the same name can denote either a namespace or a class depending on the declaration region where the name is used. For example
namespace A
{
struct A
{
static int a;
static int b;
static int c;
};
int A::a = 5;
}
int A::A::b = 10;
int A::A::c = a;
The most appropriate documentation is the C++ Standard. You may download a working draft of the Standard from the ISO-IEC site
As for the typedef that defines a type
typedef boost::shared_ptr<multi_img> ptr;
then it seems that it is defined in the class definition of multi_img. So if the name is used outside the class scope it shall be qualified
multi_img::ptr input = imginput::ImgInput(config.input).execute();
So I was learning about classes and I stumbled upon something I found was quite awkward to me.
class Nebla
{
public:
int test()
{
printout();
return x;
}
void printout()
{
printout2();
}
private:
int x,y;
void printout2()
{
cout<<"Testing my class";
}
};
I found that in a class I can use functions before I declare them (prototype them)
You can see I used printout() , printout2() before decleration.
And I can use variables also before declaring them
You can see I did return x; before declareing x.
Why can I use functions and variables in classes before declaration but outside the class if I do that, I get an error?
Thanks
Good question; I've relied on that feature for years without thinking about it. I looked through several C++ books to find an answer, including Stroustrup's The C++ Programming Language and The Annotated C++ Reference Manual, but none acknowledge or explain the difference. But, I think I can reason through it.
The reason, I believe, that your example works is that the bodies of your test and printout aren't truly where they appear in your file. The code
class MyClass {
void someFun() {
x = 5;
}
int x;
};
...which appears to violate the rule of having to declare variables before you use them, is actually equivalent to:
class MyClass {
void someFun();
int x;
};
void MyClass::someFun() {
x = 5;
}
Once we rewrite it like that, it becomes apparent that the stuff inside your MyClass definition is actually a list of declarations. And those can be in any order. You're not relying on x until after it's been declared. I know this to be true because if you were to rewrite the example like so,
void MyClass::someFun() {
x = 5;
}
class MyClass {
void someFun();
int x;
};
...it would no longer compile! So the class definition comes first (with its complete list of members), and then your methods can use any member without regard for the order in which they're declared in the class.
The last piece of the puzzle is that C++ prohibits declaring any class member outside of the class definition, so once the compiler processes your class definition, it knows the full list of class members. This is stated on p.170 of Stroustrup's The Annotated C++ Reference Manual: "The member list defines the full set of members of the class. No member can be added elsewhere."
Thanks for making me investigate this; I learned something new today. :)
Just to make it clear, this is required by the C++ Standard, not just the way several compilers handle class definitions.
N3242 3.3.7:
The potential scope of a name declared in a class consists not only of the declarative region following the name's point of declaration, but also of all function bodies, brace-or-equal-initializers of non-static data members, and default arguments in that class (including such things in nested classes).
The reason you are able to do this is because by the time you call test, printout or printout2, they will have already been created. If you call the function outside the arbitrary function before it's implementation, then you'll get an error.
Think of class member-functions as being asynchronous with the flow of evaluation of the rest of the class. This won't work with stand alone functions, but you can access data members that haven't been instantiated yet. I'm not completely sure why we are able to do this, but I think it has to do with instantitation of the class object.
Besides Philip's good response, Stroustrup gives a nice explanation of Name Lookup Rules in The Design and Evolution of C++. This is described in "6.3 Clarifications". In 6.3.1.1, "The ARM Name Lookup Rules", he mentions 2 rules defined in the ARM:
[1]The type redefinition rule:A type name may not be redefined in a class after it has been used there.
[2] The rewrite rule: Member functions defined inline are analyzed as if they were defined immediately after the end of their class declarations.
So in your case it would apply the rewrite rule (as Philip deduced), that's why you can forward reference those class members.
This book may be mainly of historical interest (it's written in '94), but I think those rules are applied the same way today.
Why can I use functions and variables in classes before declaration
This is because the body of a member function is a complete-class context of a class, as mentioned in the quoted statements below:
From class.mem.general#6:
6. A complete-class context of a class is a:
function body ([dcl.fct.def.general]),
default argument,
noexcept-specifier ([except.spec]), or
default member initializer
within the member-specification of the class.
This means that the usage of printout inside member function test and the usage of printout2 inside member function printout is allowed here even though those members appear later when writing the class definition.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ Static member method call on class instance
Today I discovered that something I had long (and I mean long—like, for twenty years), thought illegal in C++ is actually legal. Namely, calling a static member function as if it belonged to an individual object. For example:
struct Foo
{
static void bar() { cout << "Whatever."; }
};
void caller()
{
Foo foo;
foo.bar(); // Legal -- what?
}
I normally see static member functions being called strictly with "scope resolution syntax," thus:
Foo::bar();
This makes sense, because a static member function is not associated with any particular instance of the class, and therefore we wouldn't expect a particular instance to be syntactically "attached" to the function call.
Yet I discovered today that GCC 4.2, GCC 4.7.1, and Clang 3.1 (as a random sampling of compilers) accept the former syntax, as well as:
Foo* foo = new Foo;
foo->bar();
In my particular case, the legality of this expression led to a runtime error, which convinced me that the peculiarity of this syntax is of more than academic interest—it has practical consequences.
Why does C++ allow static member functions to be called as if they were direct members of individual objects—that is, by using the . or -> syntax attached to an object instance?
In The Design and Evolution of C++ at page 288, Bjarne Stroustrup mentions that in the days before static member functions, programmers used hacks like ((X*)0)->f() to call member functions that didn't need an object. My guess is that when static member functions were added to the language, access through -> was allowed so that programmers with code like that could change f to static without having to hunt down and change every use of it.
Presumably so you can call it in places where you may not know the class type of something but the compiler does.
Say I had a bunch of classes that each has a static member that returned the class name:
class Foo
{
static const char* ClassName() { return "Foo"; }
};
class Bar
{
static const char* ClassName() { return "Bar"; }
};
Then all over my code I could do things like:
Foo foo;
printf( "This is a %s\n", foo.ClassName() );
Without having to worry about knowing the class of my objects all the time. This would be very convenient when writing templates for example.
It's like this because the standard says that's how it works. n3290 § 9.4 states:
A static member s of class X may be referred to using the qualified-id
expression X::s; it is not necessary to use the class member access
syntax (5.2.5) to refer to a static member. A static member may be
referred to using the class member access syntax, in which case the
object expression is evaluated. [ Example:
struct process {
static void reschedule();
};
process& g();
void f() {
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
end example ]
From The Evolution of C++ (pdf), section 8. Static Member Functions:
...It was also observed that nonportable code, such as
((x*)0)->f();
was used to simulate static member functions.
So my guess is (based on the pattern of rationale for almost every other weird syntactical thing) they allowed invoking a static member function when you just had the type to provide backwards compatibility with an established but broken idiom.
If you don't subscribe to the "because the standard says so" school of causality, I also suggest that static methods are old enough to come from a time when people actually worried about the extra overhead from passing the this argument to a function call, so making pure functions "static" as an optimization was probably all the rage in 1985.
class C : public B
{
public:
void C::Test();
};
What is the point of specifying C in the declaration of the member function?
You shouldn't do this. Many modern compilers will treat this as a syntax error, for example, g++ 4.2.1 will!
This is only neccessary when defining the method outside of the class:
class C : public B
{
public:
void Test();
};
void C::Test() { ... }
Not only there's no point, it is downright illegal (see 8.3/1 in the language standard). In general in C++ language qualified names are allowed only when you are referring to a previously declared entity, but not when you are introducing a new entity (there are some exceptions from this rule, but none of them apply here).
The code you posted would require a diagnostic message from any conforming compiler, since your member function declaration is invalid.
There is no point, no need to do this. Since the declaration of Test is inside the scope of the declaration of C, the compiler knows that the function Test is a member of C.