When I run the following code:
#include <iostream>
class A
{
public:
virtual void foo()
{
std::cout << "Foo\n";
}
};
class B : A
{
public:
virtual void foo() override
{
A foo();
std::cout << "Bar\n";
}
};
int main()
{
B b;
b.foo();
}
I get the following result: Bar.
I understand that to get:
Foo
Bar
I would need to replace A foo(); with A::foo();.
But I'm having trouble understanding what A foo(); is, as it seems that that statement (or declaration?) is skipped.
Note: I'm using g++ 7.4 on a x86 machine.
Thanks!
A foo(); declares a function that has no arguments, returns an A and is called foo.
A::foo(); is something entirely different. It calls the method A::foo.
You are experiencing a phenomenon commonly referred to as most vexing parse. It usually manifests when trying to initialise a variable:
Type variable1;
Type variable2(value);
Type function1();
Type function2(Type);
It is easy to be misled into thinking that Type x(); and Type y(1); should roughly do a similar thing, but the former declares a function while the latter declares and defines a local variable.
In your case in the example, foo is not the member function A::foo but a local declaration of a function that would shadow the member function you are keen on calling.
The fact that this is seldom useful in function scopes is even more vexing, but that's just how the C++ parser works. Declaration syntax does not distinguish between global and local scope.
struct A
{
void f1()
{
f2(); // ok, though f2() is not declared before
}
void f2()
{}
void f3(X*) // error: unknown type name 'X'
{}
struct X
{};
};
int main()
{
A a;
}
Why do member types need to be forward declared while member functions needn't?
This has to do with the complete-class context. When you are in the body of a member function, the class is considered complete and can use anything defined in the class, no matter where in the class it is declared.
The function parameters are not part of that context so they must be types that are known about at the point you try to use them.
I'm trying to create a class prototype, however I keep getting the error: 'aClass' uses undefined class 'myClass'
I'm pretty sure I'm making the prototype properly. Using a prototype function works, however class prototype doesn't.
extern class myClass; // prototypes
extern void myFunction();
int main() // main
{
myClass aClass;
myFunction();
return 0;
}
class myClass { // this doesn't work
public:
void doSomething() {
return;
}
myClass() {};
};
void myFunction() { // this works
return;
}
myClass aClass; is a definition, which requires myClass to be a complete type; the size and layout of myClass must be known at that point, at compile-time.
Any of the following contexts requires class T to be complete:
...
definition of an object of type T;
...
That means the class has to be defined before that.
Note that forward declaration works for those cases that don't require the type to be complete, e.g. a definition of pointer to the type (like myClass* p;).
For functions the story is different. A function is odr-used if a function call to it is made, then its definition must exist somewhere. Note that the definition is not required at compile-time, defining it after main() (with declaration before) is fine.
a function is odr-used if a function call to it is made or its address is taken. If an object or a function is odr-used, its definition must exist somewhere in the program; a violation of that is a link-time error.
BTW: Using extern in forward declaration of a class is superfluous.
Why doesn't this compile?
class Test
{
void foo();
void foo()
{ }
};
But these will compile:
void bar();
void bar()
{ }
// In same header/file
class Test
{
void foo();
};
void Test::foo()
{ }
The compiler would say that given method cannot be overloaded. The method Test::foo is not being overloaded - it is the same function with exact same signature.
It's explicitly prohibited by the C++ standard. Right there at [class.mfct/1]
A member function may be defined in its class definition, in which
case it is an inline member function, or it may be defined outside of
its class definition if it has already been declared but not defined
in its class definition. A member function definition that appears
outside of the class definition shall appear in a namespace scope
enclosing the class definition. Except for member function definitions
that appear outside of a class definition, and except for explicit
specializations of member functions of class templates and member
function templates ([temp.spec]) appearing outside of the class
definition, a member function shall not be redeclared.
It is just the way it is in C++. Redeclaring a class member is not allowed (unless you consider an out-of-class definition as another declaration). Redeclaring a namespace member is OK as long as you obey ODR.
Why doesn't this compile?
class Test {
void foo();
void foo() { }; // wrong
};
Because, as StoryTeller and others answered, you are declaring and defining the same member function void Test::foo(void) twice (and the inside-class definition of foo is implicitly inline).
If you want to define a member function in your header file after the class, you'll better declare it explicitly as inline like this:
class Test {
inline void foo();
};
and later define that member function (e.g. below in the same header file):
void Test::foo() {
// body of Test::foo
}
BTW, if you declare a member function with outside definition like above, and that member function is not inline but is defined in some header file which is included in several translation units, that function would be multiply defined and the linker would complain.
void foo();
and
void foo() {}
are two ways of declaring functions in a class definition. The first only declares the function and the second declares the function and also implements it. Therefore the compiler assumes that you are going to re-declare the same function and is not a correct overload as the function signature is the same in both.
If only define this method it will have a compiler error.
void classA::testMethod() {
}
And so it must be declared first:
class classA {
void testMethod();
};
Why should these be declared?
I know for common C method methods it is not needed declare, but they can just be defined:
void test() {
}
There are several secondary reasons both objective and subjective (i.e. allows to specify visibility, serves as an interface for the class and probably several others related to compiling and linking phases and TU symbols visibility, not to mention a class is the basic encapsulation unit, with all that implies) but an unquestionable one is that the standard dictates it:
N3797 - class.mfct/p2
A member function may be defined (8.4) in its class definition, in
which case it is an inline member function (7.1.2), or it may be
defined outside of its class definition if it has already been
declared but not defined in its class definition. A member function
definition that appears outside of the class definition shall appear
in a namespace scope enclosing the class definition. Except for member
function definitions that appear outside of a class definition, and
except for explicit specializations of member functions of class
templates and member function templates (14.7) appearing outside of
the class definition, a member function shall not be redeclared.
emphasis mine.
You don't need to declare the method before you define it, but you need to declare class methods in the class. Else it wouldn't be a class method.
That may seem like a contradiction, but a definition is also a declaration. So what this means is that the definition may appear in the class itself:
class A {
void testMethod() { /*...*/ }
};
[edit]
Also, practically speaking, inside the class declaration there are private, protected and public parts. This is needed to for encapsulation. If you could declare methods outside the class, you would lose encapsulation. Anybody could access private members merely by defining extra getters and setters, even when those would not make sense. Class invariants would become meaningless.
It helps encapsulation. If you have a class A
class A {
public:
foo();
bar();
}
You can be sure that only methods foo and bar mess with the private data members of the class. (Or pointer magic or undefined behavior of course)
All of the previous answers are correct as far as they go, but
they fail to point out the reason behind the rule. In C++,
a class definition is closed; you cannot add to it later. This
is necessary for non-static data members, since they determine
the size (and the implicitly generated special functions), but
it is a basic principle in C++ for all class members: not just
data, but functions, types, etc. It is considered essential for
good encapsulation.
This is true for most (but not all) languages which support the
concept of class.
This also explains why it the situation is different for
namespaces (which aren't closed).
Note the use of the qualifier ::. It means
on the left you have a namespace or class identifier
on the right you have a namespace, class, or method / function identifier
So writing void A::testMethod() assumes that there is a class or namespace A defined - this is how C++ is defined. And this applies to
void A::testMethod();
as well as to
void A::testMethod()
{
}
Also note the global namespace where you have indeed nothing at the left of :: as in
void ::testMethod()
{
}
And by definition the global namespace is always defined so the above code defines a function similar to C-style without the qualifier.
Even if it were not mandated by the standard, there are the following two reasons why you need to declare all class methods in the class definition.
You can only declare something as public, private or protected in the class declaration, you can't do so at the method definition in the .cpp file. So what visibility would your free-standing class method have?
If the standard decided to select one of the three as the default (C++ defaults to private), and place that visibility on your method, you now have a scoping problem. Even the most restrictive visibility (private) means that you can use the method in any other member method, including those defined before it in the source file. Without the declaration in the class definition, those earlier functions would not be aware of your free standing method, thus you violate the scoping rules.
In your foo.h header:
class foo
{
public:
foo() {}
virtual ~foo() {}
declaredMethod();
};
In your foo.cpp
foo::declaredMethod()
{
...
freeStandingMethod(); // This should be legal, but it can't work since we
// haven't seen foo::freeStandingMethod() yet
...
}
foo::freeStandingMethod()
{
...
}
Even if you could make this work in the same .cpp file, it's legal to place foo::freeStandingMethod() in a different .cpp file from foo::declaredMethod() at which point this becomes impossible.
This is not an answer, but you might find it informative and fun.
Adding 2 template functions to your class will effectively allow you to call any free function that takes an object of that class as the first parameter:
#include <string>
#include <iostream>
struct puppy {
puppy(std::string name)
: _name(std::move(name))
{}
const std::string& name() const noexcept {
return _name;
}
void set_name(std::string name) {
_name = std::move(name);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args) const
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args)
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
private:
std::string _name;
};
void woof(const puppy& p) {
std::cout << "puppy " << p.name() << " woofs!" << std::endl;
}
void indented_woof(const puppy&p, size_t indent) {
std::cout << std::string(indent, ' ');
woof(p);
}
void complex_woof(const puppy& p, int woofs)
{
std::cout << "attention!" << std::endl;
for (int i = 0 ; i < woofs ; ++i) {
p.perform(indented_woof, 4);
}
}
std::string name_change(puppy& p, std::string(new_name))
{
auto old_name = p.name();
p.set_name(std::move(new_name));
return old_name;
}
int main()
{
puppy fido { "fido" };
fido.perform(woof);
fido.perform(complex_woof, 10);
auto old_name = fido.perform(name_change, "bonzo");
fido.perform(woof);
std::cout << "changed name from " << old_name << std::endl;
return 0;
}
"Methods" or "member functions" (as is the more common terminology in C++) are part of the class declaration. Since you must declare a C++ class in one single place, you must make sure that all "member functions" (or "methods") are already present in that declaration.
I know for common C method methods it is not needed declare, but they
can just be defined
When you refer a "common C method" in C++, you actually mean a "common function". Note that you can declare classes anywhere you can declare such functions.
Also, note that you can declare a member function with a body. You do not have to separate declaration and definition. I.e. this is perfectly valid:
class A{
void privateMethod() {
// do something here...
}
public:
void publicMethod() {
// do something here...
}
};
why should declare these? I know for common c method, there is no need to declare, instead of it just define it:
There is no method in C, just attribute of an struct, wich can be function Pointeur, then associated to a function addresse.
Furthermore you have to declare it in the class definition for the same reason you do it in C:
The compilateur will transform this pre-declaration into a function pointeur then associate to the said methode int the construction of your object.
If a definition of a C++ class should be transformed to a C struct the code would be like this:
struct Aclass {
void (*Amethode))(int);
}
void Amethode(int) { return (0); }
Aclass primaryObject = {&Amethode};
Aclass* AclassConstructor() {
Aclass* object;
object = malloc(sizeof(Aclass));
memcpy(object, primaryObject, sizeof(Aclass));
return (object);
}