30

Is there a way to avoid the Graph:: repetition in the implementation file, yet still split the class into header + implementation? Such as in:

Header File:

#ifndef Graph_H
#define Graph_H

class Graph {
public:
    Graph(int n);
    void printGraph();
    void addEdge();
    void removeEdge();
};

#endif

Implementation File:

Graph::Graph(int n){}
void Graph::printGraph(){}
void Graph::addEdge(){}
void Graph::removeEdge(){}
GManNickG
  • 494,350
  • 52
  • 494
  • 543
Ofek Ron
  • 8,354
  • 13
  • 55
  • 103
  • 1
    This looks right, assuming you don't forget to `#include` the header in the implementation. – Sergey Kalinichenko Jun 04 '12 at 19:39
  • 4
    Are you asking if you can avoid typing `Graph::` in the implementation? – GManNickG Jun 04 '12 at 19:39
  • 3
    I know it is right, but im asking if there is another way without having to repeat Graph::.. – Ofek Ron Jun 04 '12 at 19:40
  • 6
    This is far from a very onerous task and not something I've ever actively felt a need to avoid. My first reaction was 'wow, what a thing to complain about'. But after I thought about it, it would be both feasible, hyper-convenient, and semantically/organisationally useful if there were a keyword/combo such as **`class namespace Thingy {`** that meant everything within its braces were implicitly qualified with `Thingy::`. Not mentioned in OP, but this'd obviously cover definitions of `static` variables too. Seems a very logical extension of `namespace`. Folks, remember, you heard it here first! – underscore_d Jul 08 '16 at 17:47
  • 2
    I might as well try! https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-proposals/6nF0H-GzFpo – underscore_d Jul 08 '16 at 18:20
  • 1
    Heh, quoting T.C.: "You are a bit late to the party: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0223r0.html " - Well, great minds and all that ;-) The point is made very well there that **this _is very_ relevant especially for `template class`es**, which now that I remember those difficult coding days I'd just managed to forget... their syntax is currently abominable for out-of-line definitions. And the first, independent incarnation of this was first proposed in 2003, wow. No doubt people were wondering the same thing well before that. Maybe one day... – underscore_d Jul 08 '16 at 19:16
  • @underscore_d I'd be especially keen if `auto` was possible for the definition, so that `template template FooLongClassName & FooLongClassName::operator = (const U &) { /* code */ return *this; }` could become `template auto & operator = (const U &) { /* code */ return *this; }`. – Elliott Sep 28 '20 at 10:19

8 Answers8

15

I'm guessing this is to avoid lots of "unnecessary typing". Sadly there's no way to get rid of the scope (as many other answers have told you) however what I do personally is get the class defined with all my function prototypes in nice rows, then copy/paste into the implementation file then ctrl-c your ClassName:: on the clip board and run up the line with ctrl-v.

Kneight
  • 166
  • 2
13

If you want to avoid typing the "Graph::" in front of the printGraph, addEdge etc., then the answer is "no", unfortunately. The "partial class" feature similar to C# is not accessible in C++ and the name of any class (like "Graph") is not a namespace, it's a scope.

Viktor Latypov
  • 14,289
  • 3
  • 40
  • 55
5

No there's not. Not directly at least. You could go for preprocessor tricks, but don't do it.

#define IMPL Graph::

IMPL Graph(int n){}
void IMPL printGraph(){}
void IMPL addEdge(){}
void IMPL removeEdge(){}

Also, you shouldn't even want to do it. What's the point. Besides it being a C++ rule, it lets you know you're actually implementing a member function.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 3
    Eh, is it really wise to say "Don't do this...here's how!"? – GManNickG Jun 04 '12 at 19:44
  • 3
    You could also define them in a separate file and `#include` them in the body of the class. – Pubby Jun 04 '12 at 20:05
  • @Pubby: That's so disgusting, I LOVE IT!!! Foo.h `class Foo { int foo (); };`, Foo.ns `Foo::`, Foo.cpp `void #include "Foo.ns" foo () { return 1 }` (newlines around the #include) – Thomas Eding Jun 13 '12 at 20:50
  • Nah, bad solution, but for one single reason only: The name of the macro is too long, so it does not safe enough typing! Should be named `I` (referring to "IMPL") or `G` (referring to "Graph::"). – Aconcagua Feb 22 '18 at 10:10
  • Hm, I feel it already right know, there surely will be someone not noticing the irony in my previous comment... – Aconcagua Feb 22 '18 at 10:11
  • -1 because you've said this is something that we shouldn't want. Often these method definitions are grouped into the one cpp file for the same type, so if it were possible to scope the definition like we can the declaration then it would be clear, concise AND explicit. If your class is a specialisation with a few template arguments, such as self-explaining enums, etc, and your code is well written into small methods, then it can end up being > 50% repetition of the long class name. – Elliott Feb 03 '20 at 05:02
5

One option is using. If you have method definitions which are in a cpp file that never gets #included, then using is safe (doesn't affect other files):

foo.h:

class FooLongNameSpecialisationsParamaters
{
    int x_;

public:

    int Get () const;
    void Set (int);
};

foo.cpp:

#include "foo.h"

using Foo = FooLongNameSpecialisationsParamaters;

int Foo::Get () const
{
    return x_;
}

void Foo::Set (int x)
{
    x_ = x;
}

main.cpp:

#include "foo.h"

int main ()
{
    //Foo foo; <-- error
    FooLongNameSpecialisationsParamaters foo;

    return 0;
}
Elliott
  • 2,603
  • 2
  • 18
  • 35
2

No, there is no way to avoid it. Otherwise, how would you know if a given function definition is for a class function or for a static function?

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • 2
    You are, of course, correct for the current Standard. I'd like to pretend you were speaking hypothetically, though ;-) So as per my comments to the OP: You'd disambiguate very easily by using the proposed `namespace class` to define the members: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0223r0.html - and wow, do I hope this is adoped... & am very sad it seems to have missed C++17 :( If anyone judges this trivial on a DRY basis, just think about (A) the intuitive parallels to normal `namespace` & especially (B) implementing `template` functions out-of-line, which is excruciating. – underscore_d Jul 08 '16 at 21:44
2

If you are asking if you can define a member function such as Graph::printGraph without specifying the class name qualification, then the answer is no, not the way that you want. This is not possible in C++:

implementation file:

void printEdge(){};

The above will compile just fine, but it won't do what you want. It won't define the member function by the same name within the Graph class. Rather, it will declare and define a new free function called printEdge.

This is good and proper, if by your point of view a bit of a pain, because you just might want two functions with the same name but in different scopes. Consider:

// Header File
class A
{
  void foo();
};

class B
{
  void foo();
};

void foo();

// Implementation File
void foo()
{
}

Which scope should the definition apply to? C++ does not restrict you from having different functions with the same names in different scopes, so you have to tell the compiler what function you're defining.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
1
        //yes it is possible using preprocessor like this:

        #define $ ClassName //in .cpp 

    void $::Method1() 
    { 
    } 

    //or like this: in the header .h:

        #undef $
        #define $ ClassName' 

// but you have to include the class header in last #include in your .cpp:

        #include "truc.h"
        #include "bidule.h" ...
        #include "classname.h" 

        void $::Method() { }  

        //i was using also 
        #define $$ BaseClass 
        //with single inheritance  than i can do this: 

        void $::Method() 
        { 
        $$::Method(); //call base class method 
        } 

        //but with a typedef defined into class like this it's better to do this: 
        class Derived : Base 
        { 
        typedef Base $$;  

    }
david
  • 27
  • 1
0

EDIT: I misread your question. This would be an answer to the question whether you can split header-files. It doesn't help you to avoid using LongClassName::-syntaxes, sorry.

The simple answer: You can split up c++-file, but you can not split up header-files.

The reason is quite simple. Whenever your compiler needs to compile a constructor, it needs to know exactly how many memory it needs to allocate for such an object.

For example:

class Foo {
   double bar;  //8 bytes
   int goo;  //4 bytes
}

new Foo() would require the allocation of 12 bytes memory. But if you were allowed to extend your class definitions over multiple files, and hence split header files, you could easily make a mess of this. Your compiler would never know if you already told it everything about the class, or whether you did not. Different places in your code could have different definitions of your class, leading to either segmentation faults or cryptic compiler errors.

For example:

h1.h:

class Foo {
   double bar;  // 8 bytes
   int goo;     // 4 bytes
}

h2.h: #include "h1.h"

class Foo {
   double goo;   // 8 bytes
} // we extend foo with a double.

foo1.cpp:

#include "foo1.h"

Foo *makeFoo() {
   return new Foo();

}

foo2.cpp:

#include "foo2.h"

void cleanupFoo(Foo *foo) {
   delete foo;
}

foo1.h:

#include "h1.h"

Foo *makeFoo();

foo2.h:

#include "h1.h"
#include "h2.h"

void cleanupFoo(Foo *foo)

main.cpp:

#include foo1.h
#include foo2.h

void main() {
    Foo *foo = makeFoo();
    cleanupFoo(foo);
}

Carefully check what happens if you first compile main.cpp to main.o, then foo1.cpp to foo1.o and foo2.cpp to foo2.o, and finally link all of them together. This should compile, but the makeFoo() allocates something else then the cleanupFoo() deallocated.

So there you have it, feel free to split .cpp-files, but don't split up classes over header files.

Herbert
  • 5,279
  • 5
  • 44
  • 69
  • This isn't what the OP was asking. They've pointed out that if you define a class and its methods together then you can avoid repeating the class name for each method definition. But if you define the class (only declaring its methods) then define the methods in another file (as we typically do), then we must keep repeating the full class name before each method definition. – Elliott Feb 03 '20 at 05:10
  • you are right, this wasn't as clear from the original question, which was changed a bit before I wrote my answer. I would think, **8 years ago**, I wrote the answer and while writing the question changed. – Herbert Feb 03 '20 at 12:46
  • Fair enough. That sounds annoying. But either way, these answers still get viewed (I came across this because yesterday I searched for a solution to this problem, and wanted something better than my solution [which I've left as an answer]). – Elliott Feb 04 '20 at 02:37
  • 1
    @Elliott-ReinstateMonica Do you want my answer changed in some way? Feel free to suggest :) – Herbert Feb 04 '20 at 10:42
  • Thanks for thinking constructively! The edit was there already, yesterday I just removed some typo's and ugly lay-outing that were annoying me :) – Herbert Feb 06 '20 at 10:34
  • An `int` may not be size 4. Most implementations use 8 bits per byte, but that can change. Additionally, the standard implies a minimum number of bits, but an implementation can use more (and also store larger numbers than the standard demands). A `double` is only required to be as large as a `float`, meaning it could easily be smaller than 4 bytes. Take a look here: https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be – user904963 Nov 30 '21 at 12:38