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.
Related
For the time I'm learning to code with boost/asio. Many code samples make use of the combination of async_accept and bind. In the server code , i come across some thing like this:
class Tcp_server
{
public:
Tcp_server()
{
}
void start_accept(int a)
{
if(a>0)
{
cout<<a<<endl;
handle_accept(a-1);
}
}
void handle_accept(int a)
{
if(a>0)
{
cout<<a<<endl;
start_accept(a-1);
}
}
};
If i make an instance of Tcp_server and call either handle_accept or start accept, it works. But if I drop the Tcp_server class encapsulation, the compiler would complain "handle_accept is not declared". I'm just wondering if the compiler automatically forward declare all the functions defined in the same class. Can anyone explain why?
Functions defined in the definition of a class have exactly the same semantics as if they are only declared in the class definition and then defined immediately after the class definition. The only difference is that such member functions are implicitly declared inline while a function definition is either not-inline or explicitly inline. That is, from the compiler's point of view the functions are declared and the class is defined before the function definitions are considered.
The reason for defining the function after the class definition is simple: without doing so, the class would be incomplete and look-ups of members would fail which is clearly not desirable for member function definitions. As a side effect, functions can readily refer to each other. Since defining member functions in the class definition is primarily for convenience it would also be somewhat inconvenient to require declaration for member functions used later.
I always thought that if I declare member of a class inside class this member is known at the entire scope of a class that is:
class X
{
public:
X(int a) :v_(a)
{}
private:
int v_;//even though v_ is declared here I'm using it in ctor which is above this line
};
So that makes sense to me.
Anyhow this doesn't because I'm getting error that v_ isn't known
class X
{
public:
X(decltype(v_) a) :v_(a)//error on this line, compiler doesn't know v_
{}
private:
int v_;
};
Would be glad to learn why.
I'm using intel compiler v14 SP1
Thank you.
3.3.7 Class scope
1 The following rules describe the scope of names declared in classes.
1) 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).
...
That means that you can use v_ in function bodies, constructor initializer lists and default arguments. You are not allowed to use v_ in parameter declarations the way you used it in your code.
For example, this shall compile
class X
{
public:
X(int a = decltype(v_)()) : v_(a)
{}
private:
int v_;
};
but not the second example in your original post.
Your code compiles with Clang.
Reading C++11 specifications you are not allowed to declare the variable after it is being used as function/constructor parameter.
In many cases classes including function signatures will be defined in headers, but function bodies in cpp files. Since the header will have been read by the compiler at the start of reading the cpp file, this problem does usually not occur. But indeed, C++ compilers don't look ahead.
I've been learning C++, and I've come across static variable (I have prior knowledge from C89), and in the resource i'm using, they've declared a static variable in a class such as:
class nameHere
{
public:
static int totalNum;
}
int nameHere::totalNum = 0;
int main()
{}
For Example.
What I don't understand is that, since I've already declared that the static variable is an integer in the class definition, why do I need to also declare it as an integer outside of the class definition?
Would it not make sense to simply initialise it like so:
nameHere::totalNum = 0;
int main()
{}
Is there a particular reason or simply a convention of C++?
Thanks for all the help!
This would (probably) make the language even more difficult to parse (and it's already almost insanely difficult to parse anyway).
As it is, the datatype (int, long, my_class, whatever) tells the compiler that what it's seeing is the beginning of a declaration (which, in this case, is also a definition). Without that, the compiler would have a rather more difficult time sorting things out.
In the specific case of things at global scope, it wouldn't be that bad, because at global scope about all you can have is a series of declarations. At any other scope, however, things would be more difficult (and having one rule at global scope, and another elsewhere would be ugly indeed).
In C++11 you can simply initialize the variable inside the class:
class nameHere
{
public:
static const int totalNum = {0};
}
There is a difference between a definition and a declaration.
While the static variable in the class has been declared, it has not been defined. The One Definition Rule, explains declarations and definitions and states
In any translation unit, a template, type, function, or object can have no more than one definition. Some of these can have any number of declarations.
Therefore, the full type of the object must be used when declaring the variable.
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.