Function declaration inside or outside the class
Asked Answered
R

8

109

what the best practice is for standard function declarations.

In the class:

class Clazz
{
 public:
    void Fun1()
    {
        //do something
    }
}

Or outside:

class Clazz
{
public:
    void Fun1();
}

Clazz::Fun1(){
    // Do something
}

I have a feeling that the second one can be less readable...

Rasure answered 31/1, 2012 at 7:30 Comment(6)
There are actually 3 options here. Your second example could have the function definition in the header file (but still not inlined), or in a separate .cpp file.Kinlaw
This question might help you understand.Granulate
Just a note: declaration is always inside the class, but definition is either inside or outside. The question title and body should be subjected to s/declaration/definition/ Don't believe me? https://mcmap.net/q/15925/-what-is-the-difference-between-a-definition-and-a-declaration/1143274Memorialist
Function definitions inside class must be avoided. They are deemed implicitly inline.Naucratis
@JohnStrood so? inline only relaxes the one definition rule, which is necessary if another translation unit uses ClazzRubidium
There are no strict rules in C++ about this, more like guidelines. Typically it is recommended to put definitions in a separate .cpp-file and have the declaration of the class in the header to hide the implementation. It will become self-evident once you get more experience programming C++, I will not spoil the fun.Bono
B
65

C++ is object oriented, in the sense that it supports the object oriented paradigm for software development.

However, differently from Java, C++ doesn't force you to group function definitions in classes: the standard C++ way for declaring a function is to just declare a function, without any class.

If instead you are talking about method declaration/definition then the standard way is to put just the declaration in an include file (normally named .h or .hpp) and the definition in a separate implementation file (normally named .cpp or .cxx). I agree this is indeed somewhat annoying and requires some duplication but it's how the language was designed (the main concept is that C++ compilation is done one unit at a time: you need the .cpp of the unit being compiled and just the .h of all the units being used by the compiled code; in other words the include file for a class must contain all the information needed to be able to generate code that uses the class). There are a LOT of details about this, with different implications about compile speed, execution speed, binary size and binary compatibility.

For quick experiments anything works... but for bigger projects the separation is something that is practically required (and it's not clear cut... it may make sense to keep SOME implementation details in the public .h).

If you're looking for a logical explanation of why this split is necessary you won't find one. Because there's none. The compiler could still use the one-compilation-unit-at-a-time model with just one file (by considering only the interface details, even if the implementation is in the same file). But this is C++, so you're forced to do the split and repeat things twice without making mistakes (otherwise it's YOUR fault if the code doesn't work: compilers are not required to detect all incompatibilities between what is in the .h and what is in .cpp; some are detected and some are not and just will (possibly) destroy all data on your computer if you make that kind of mistake). The reason is mostly "because" (my own rationalization is may be keeping the compiler simpler and that back then it was considered an important "feature" being able to publish .h files and keep implementations secret).

Note: Even if you know Java, C++ is a completely different language... and it's a language that cannot be learned just by experimenting. The reason is that it's a rather complex language with a lot of asymmetries and apparently illogical choices, and most importantly, when you make a mistake there are no "runtime error angels" to save you like in Java... but there are instead "undefined behavior daemons".

The only reasonable way to learn C++ is by reading... no matter how smart you are there is no way you can guess what the committee decided (actually being smart is sometimes even a problem because the correct answer is illogical and a consequence of historical heritage.)

Just pick a good book or two and read them cover to cover in addition to experimenting. Experimenting alone will take you nowhere near a decent level of C++ proficiency.

Barn answered 31/1, 2012 at 7:43 Comment(7)
If someone comes from Java and asks for help on C++, then what does it tell him if you say "the language you know is obsessed with something"? He doesn't have a comparison to other languages, so this tells him pretty much nothing. Better than using a stronly emotionally connotated word like obsessed, which doesn't tell the OP much, you might consider just leaving this part out. Moreover, what is the context of "use a class for everyting"? In Java, you do not use a class for a method. You do not use a class for a variable. You do not use a class for a file..So what's "everything" here? Ranting?Trifid
@DanielS: Removed that part because apparently offended you (no idea why). For sure I'm not ranting about Java because I don't actually use Java at all, I simply thought at the time that OOP as Object Obsessed Programming was a funny joke, while apparently it is not. I've been a Java 1.1 certified programmer but decided back then that, unless forced for some reason, I will not use that "programming language" and so far I succeeded in avoiding it.Barn
Thanks, I think it reads much better now. Sorry if I sound offended. I will try to be more positive next time.Trifid
Does not answer the questionGrind
@PetrPeller: what is the part of the third paragraph that is not clear to you?Barn
"undefined behaviour deamons" - I guess I prefer nasal deamonsGrahamgrahame
"what is the part of the third paragraph that is not clear to you?" well I know this answer is nearly 10 years old now but a) it's far and away the highest rated answer here and b) you talk a lot about standard ways of doing things and mention that separation into declaration and definition is "practically required" without talking at all about what the practical differences between the two methods are, which is what the question originally asked.Ellsworth
J
34

The first defines your member function as an inline function, while the second doesn't. The definition of the function in this case resides in the header itself.

The second implementation would place the definition of the function in the cpp file.

Both are semantically different and it is not just a matter of style.

Jamajamaal answered 31/1, 2012 at 7:32 Comment(1)
cplusplus.com/doc/tutorial/classes gives the same answer: "The only difference between defining a class member function completely within its class or to include only the prototype and later its definition, is that in the first case the function will automatically be considered an inline member function by the compiler, while in the second it will be a normal (not-inline) class member function, which in fact supposes no difference in behavior."Spathose
T
22

Function definition is better outside the class. That way your code can remain safe if required. The header file should just give declarations.

Suppose someone wants to use your code, you can just give him the .h file and the .obj file (obtained after compilation) of your class. He does not need the .cpp file to use your code.

That way your implementation is not visible to anyone else.

Triangle answered 31/1, 2012 at 11:47 Comment(0)
F
14

The "Inside the class" (I) method does the same as the "outside the class" (O) method.

However, (I) can be used when a class is only used in one file (inside a .cpp file). (O) is used when it is in a header file. cpp files are always compiled. Header files are compiled when you use #include "header.h".

If you use (I) in a header file, the function (Fun1) will be declared every time you include #include "header.h". This can lead to declaring the same function multiple times. This is harder to compile, and can even lead to errors.

Example for correct usage:

File1: "Clazz.h"

//This file sets up the class with a prototype body. 

class Clazz
{
public:
    void Fun1();//This is a Fun1 Prototype. 
};

File2: "Clazz.cpp"

#include "Clazz.h" 
//this file gives Fun1() (prototyped in the header) a body once.

void Clazz::Fun1()
{
    //Do stuff...
}

File3: "UseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz;
MyClazz.Fun1();//This does Fun1, as prototyped in the header.

File4: "AlsoUseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz2;
MyClazz2.Fun1();//This does Fun1, as prototyped in the header. 

File5: "DoNotUseClazzHeader.cpp"

//here we do not include Clazz.h. So this is another scope. 
class Clazz
{
public:
    void Fun1()
    {
         //Do something else...
    }
};

class MyClazz; //this is a totally different thing. 
MyClazz.Fun1(); //this does something else. 
Furious answered 14/10, 2013 at 5:9 Comment(1)
You mean Clazz MyClazz and Clazz MyClazz2?Electrolyte
C
4

Member functions can be defined within the class definition or separately using scope resolution operator, ::. Defining a member function within the class definition declares the function inline, even if you do not use the inline specifier. So either you can define Volume() function as below:

class Box
{
  public:

     double length;
     double breadth;    
     double height;     

     double getVolume(void)
     {
        return length * breadth * height;
     }
};

If you like you can define same function outside the class using scope resolution operator, :: as follows

double Box::getVolume(void)
{
   return length * breadth * height;
}

Here, only important point is that you would have to use class name just before :: operator. A member function will be called using a dot operator (.) on a object where it will manipulate data related to that object only as follows:

Box myBox;           

myBox.getVolume();  

(from: http://www.tutorialspoint.com/cplusplus/cpp_class_member_functions.htm) , both ways are legal.

I'm not an expert, but I think, if you put only one class definition in one file, then it does not really matter.

but if you apply something like inner class, or you have multiple class definition, the second one would be hard to read and maintained.

Camilia answered 10/9, 2014 at 18:31 Comment(1)
Can you bring the relevant content from that link into the body of your post, and thus future-proofing against dead links? ThanksSalary
L
2

The first one must be put in the header file (where the declaration of the class resides). The second can be anywhere, either the header or, usually, a source file. In practice you can put small functions in the class declaration (which declares them implicitly inline, though it's the compiler that ultimately decides whether they will be inlined or not). However, most functions have a declaration in the header and the implementation in a cpp file, like in your second example. And no, I don't see any reason why this would be less readable. Not to mention you could actually split the implementation for a type across several cpp files.

Lamar answered 31/1, 2012 at 7:35 Comment(0)
B
2

A function that is defined inside a class is by default treated as an inline function. A simple reason why you should define your function outside:

A constructor of the class checks for virtual functions and initializes a virtual pointer to point to the proper VTABLE or the virtual method table, calls the base class constructor, and initializes variables of the current class, so it actually does some work.

The inline functions are used when functions are not so complicated and avoids the overhead of the function call. (The overhead includes a jump and branch on the hardware level.) And as described above, the constructor is not as simple to be considered as inline.

Bourne answered 5/10, 2016 at 11:45 Comment(1)
"inline" has practically nothing to do with inlining. The fact that member functions defined in-line are implicitly declared inline is there to avoid ODR violations.Burgee
G
1

Inline functions(functions when you declare them in the class ) every time when call them they are pasted in your main memeory code. While when you declare the function outside the class, the when you call the fuction it comes from the same memory. Thats why it is much better.

Gesellschaft answered 20/10, 2020 at 14:31 Comment(1)
Would you add any reference? It looks like you mentioning size of memory. How about time accessing the memory?Upthrow

© 2022 - 2024 — McMap. All rights reserved.