tags:

views:

1326

answers:

16

Hi guys, I'm an old(but not too old) Java programmer, that decided to learn C++. But I have seen that much of C++ programming style, is... well, just damn ugly!

All that stuff of putting the class definition in a header file, and the methods in a different source file; Calling functions out of nowhere, instead of using methods inside classes; All that just seems... wrong!

So finally, is there any reason for me to continue with this massacre to the OOP, and anything that is good and righteous in programming, or can I just ignore that old-fashioned C++ conventions, and use my good Java programing style?

By the way I'm learning C++ because I want to do game programing.

Here is an example:

In an C++ website I found a windows implementation:

class WinClass
{
public:
    WinClass (WNDPROC wndProc, char const * className, HINSTANCE hInst);
    void Register ()
    {
        ::RegisterClass (&_class);
    }
private:
    WNDCLASS _class;
};

That class is located in a header file and the constructor:

WinClass::WinClass (WNDPROC wndProc, char const * className, HINSTANCE hInst)
{
    _class.style = 0;
    _class.lpfnWndProc = wndProc;  // Window Procedure: mandatory
    _class.cbClsExtra = 0;
    _class.cbWndExtra = 0;
    _class.hInstance = hInst;           // owner of the class: mandatory
    _class.hIcon = 0;
    _class.hCursor = ::LoadCursor (0, IDC_ARROW); // optional
    _class.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // optional
    _class.lpszMenuName = 0;
    _class.lpszClassName = className;   // mandatory
}

Is located at a .cpp source file.

What I could just do is:

class WinClass
{
   public:
   WinClass (WNDPROC wndProc, char const * className, HINSTANCE hInst)
   {
       _class.style = 0;
       _class.lpfnWndProc = wndProc;  // Window Procedure: mandatory
       _class.cbClsExtra = 0;
       _class.cbWndExtra = 0;
       _class.hInstance = hInst;           // owner of the class: mandatory
       _class.hIcon = 0;
       _class.hCursor = ::LoadCursor (0, IDC_ARROW); // optional
       _class.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // optional
       _class.lpszMenuName = 0;
       _class.lpszClassName = className;   // mandatory
}
    void Register ()
    {
        ::RegisterClass (&_class);
    }
private:
    WNDCLASS _class;
};

And now the constructor is inside its class.

+5  A: 

Find a style that works for you, just like everyone else did. Nobody is forcing you to use one of the "ugly" styles, unless it's your employer enforcing a guidelines document. ;-)

Though keep in mind that placing member function definitions inside the class as opposed to outside has different semantics. When you define a member function inside the class, it's implicitly inline, for better or worse.

Julienne Walker
I think the poster is just asking if there is a reason other than tradition that C++ classes are usually broken into header and implementation files.
brian
+2  A: 

If you want to implement all your methods inside your class definitions, you will have big monster header files (it's not a good idea to declare classes in cpp files) and possibly only one cpp file (the one that has your main function).

So it's a matter of convenience.


Edit:

I find the declaration-implementation separation actually helpful. When I have monster classes with ~150 methods whose implementation is generated using lots of preprocessor tricks, I often want to be able to tell the difference between...

  • what the class can do (its interface, given by its declaration)
  • how the class does it (its implementation)

Not being able to do that in either C# or Java is quite frustrating, especially when I don't have Intellisense at hand.

Eduardo León
I could see it with the lack of intellisense, but I love the navigational features in C# like collapsing regions and the drop down menu of all of the methods in the class.
Steven Behnke
When I use Visual Studio, I use regions a lot, no matter whether I'm using C++ or C#. I don't know any Java IDE that offers such a possibility.
Eduardo León
A: 

I worry from the tone of your question that you may be reading some bad C++ code in learning C++. Well-written code is usually not ugly in any language. As a starting point, you might try the online C++ FAQ, especially the chapter on learning C++.

Kristo
A: 

The style you program in is up to you. Just make sure you understand that "ugly" style others use.

Jim C
A: 

If you want to do game programming, you probably want to work with other C++ developers, and this means you have to do things in a way they'll understand. If you hope to have any collaboration at all, your code will have to be in a reasonable C++ style. If you intend to be a lone developer, and have your code essentially die with you, use any style you like.

Moreover, C++ and Java are two different languages, and need to be used in different ways. There are reasons for the header files (think of it as declaring the interface), for example.

David Thornley
+10  A: 

.h and .cpp files often separate declarations from definitions, and there is some kind of order here, and conceptual encapsulation. headers have the 'what', implementation files have the 'how'.

I find having everything in one file in java to be disorganized. So, each to their own.

C++ conventions and idioms all have well thought out reasoning, just like any other language does for the idioms its community adopts.

I think it's best to java (as a verb) when you write Java, and to C++ when you C++! You'll appreciate why with experience of the language. Same as switching to any new language.

Scott Langham
+7  A: 

That's called seperating interface and implementation. That allows clients to figure out how to call your class without having to wade through all the code too. Frankly I think it's practically insane that people could consider it "wrong".

However, you will be quite pleased to find out that many C++ developers agree with you on that score. So go ahead and put your entire implementation in *.h files. There's a school of style out there that agrees with you.

T.E.D.
I think you could consider said separation it insufficient in C++. The amount of information necessary to expose for class definitions and template functions is extraordinary, compared to C-style interfaces (or non-template pimplized C++). Given that, I can see the draw towards header-only libs.
Tom
+15  A: 

When the code builds, the C++ preprocessor builds a translation unit. It starts with a .cpp file, parses the #includes grabbing the text from the headers, and generates one great big text file with all the headers and the .cpp code. Then this translation unit gets compiled into code that will run on the platform you're targeting. Each translation unit ends up as one object file.

So, .h files get included in multiple translation units, and a .cpp file just gets included in one.

If .h files contain lots of stuff (including implementation), then the translation units would be correspondingly bigger. Compile times would increase, and when you change anything in a header... every translation unit that uses it would need to be recompiled.

So.. minimizing stuff in .h files drastically improves compile time. You can edit a .cpp file to change a function, and only that one translation unit needs to be rebuilt.

To complete the story on compiling...
Once all the translation units are build into object files (native binary code for you platform). The linker does its job, and stitches them together into you .exe, .dll or .lib file. A .lib file can be linked into another build so it can be reused in more than one .exe or .dll.

I suppose the Java compilation model is more advanced, and the implications of where you put your code have less meaning.

Scott Langham
Please provide a reference to large scale programming and strategies for reducing compilation times for the sake of completeness.
questzen
+1 for the detailed explanation
questzen
There's this: http://www.amazon.com/Large-Scale-Software-Addison-Wesley-Professional-Computing/dp/0201633620
Scott Langham
And this: http://stackoverflow.com/questions/373142/what-techniques-can-be-used-to-speed-up-c-compilation-times
Scott Langham
+18  A: 

In addition to what others have said here, there are even more important problems:

1) Large translation units lead to longer compile times and larger object file sizes.

2) Circular dependencies! And this is the big one. And it can almost always be fixed by splitting up headers and source:

// Vehicle.h
class Wheel {
private:
    Car& m_parent;
public:
    Wheel( Car& p ) : m_parent( p ) {
        std::cout << "Car has " << m_parent.numWheels() << " wheels." << std::endl;
    }
};

class Car {
private:
    std::vector< Wheel > m_wheels;
public:
    Car() {
        for( int i=0; i<4; ++i )
            m_wheels.push_back( Wheel( *this ) );
    }
    int numWheels() {
        return m_wheels.size();
    }
}

No matter what order you put these in, one will always be lacking the definition of the other, even using forward declarations it won't work, since in the function bodies we are using specifics about each Class's symbol (which is why forward declarations won't help us here).

But if you split them up into proper .h and .cpp files and use forward declarations it will satisfy the compiler:

//Wheel.h
//-------
class Car;

class Wheel {
private:
    Car& m_parent;
public:
    Wheel( Car& p );
};

//Wheel.cpp
//---------
#include "Wheel.h"
#include "Car.h"

Wheel::Wheel( Car& p ) : m_parent( p ) {
        std::cout << "Car has " << m_parent.numWheels() << " wheels." << std::endl;
}

//Car.h
//-----
class Wheel;

class Car {
private:
    std::vector< Wheel > m_wheels;
public:
    Car();
    int numWheels();
}

//Car.cpp
//-------
#include "Car.h"
#include "Wheel.h"

Car::Car() {
        for( int i=0; i<4; ++i )
            m_wheels.push_back( Wheel( *this ) );
}

int Car::numWheels() {
        return m_wheels.size();
}

Now the code that actually has to know specifics about the second class can just include the header file which doesn't need to know specifics about the first class.

Headers just provide the declarations while Source files provide the defintions. Or another way to say it: Headers tell you what is there (what symbols are valid to use) and Source tells the compiler what the symbols actually do. In C++ you don't need anything more than a valid symbol to begin using what ever it is.

Trust that C++ has a reason for this idiom, b/c if you don't you will make a lot of head aches for your self down the line. I know :/

Adam
this is the only answer i found that actually is not like "java does it wrong; separation is good" but actually provides reason for why it is that it is. You could mention that c++ is compiled in one-pass, and that there are special constructs supporting that style (forward-declaration)
Johannes Schaub - litb
and that there doesn't exist a module concept, and thus header files are required to provide the information normally found in meta information about modules.
Johannes Schaub - litb
those two points roughly correspond to your two points, but your points explain the syntoms (large headers (because of missing modules) / circular dependencies (remember: compiling two pass, there are no circular dependency problems anymore)).
Johannes Schaub - litb
+3  A: 

That's not ugly at all.

I would say it is... mhhh different.

Bringing your old style to a new platform, that's ugly ( I have had a lot of discussions about this with Mr. Skeet )

Remember java was defined years after C++ so it is reasonable they've fixed some constructs ( In the same fashion C# learn from Java )

So, I would suggest to keep in that C++ style.

Think about this. header files are like interface declarations and cpp files are implementation.

I think C++ does not have "interface" keyword, and this is the way you separate the interface of a class from its implementation.

Similar to this in Java

public interface Some { 
    public void method();
}

public class SomeImpl implements Some { 
  public void method(){}
}
OscarRyz
+2  A: 

If you are writing a C++ DLL and you put any code in the headers, you will end up with a hard to debug mess. The DLL will contain the code from the .cpp files but the users of the DLL will have some of the code inlined into themselves.

This is really bad in Windows where you run into things like different heap allocators in different parts of the program and if you change the implementation, callers of your DLL will be using old code from the inlined headers.

Zan Lynx
+8  A: 

Most answers are about the separation of headers and compilation units. I agree with most, you must use it because it is more efficient, cleaner, more user friendly to coworkers or just because... (and you will notice the compilation time advantage not too long from now).

Anyway I just wanted to post on the other part of the question: is C++ an OOP masacre?

C++ is a multiparadigm language. It allows procedural, object oriented and generic programming. And that is a virtue, not a defect. You can still use pure OOP if you wish, but your code will surely benefit from learning and knowing when to use other paradigms.

As an example, I dislike utility classes, where all member functions are static, and there is no data. There is no reason to create a utility class more than just grouping together a set of free functions under a common name. You must do it in Java, as it insists on pure OO syntax which, as commeted by Tom, is not the same as real OO. In C++ defining a namespace and a set of free functions offers a similar solution without you needing to lock the creation of objects by declaring a private constructor or else allowing users to instantiate non-sense objects from an empty class.

To me, experience (I was once a Java-only programmer) has taught me that there are different tools that better fit different problems. I am yet to find a golden hammer and the advantage of C++ is that you can choose a different hammer for each different task, even in the same compilation unit.

Correction: litb informs me in a comment that WNDCLASS is a struct in the win32 API. So that the criticism of the class not using initialization lists is plain nonsense and as such I am removing it.

David Rodríguez - dribeas
well i think WNDCLASS is a struct of the Win32 API. it doesn't have a constructor that takes the parameters so he cannot use an initializer list :)
Johannes Schaub - litb
Nitpick - I wouldn't say Java enforces "pure OO", I would say it enforces "pure OO syntax". It's a common fallacy that Java == OO just because of the objects (^:
Tom
I wish I could upvote Tom's comment as well.
Max Lybbert
+5  A: 

Calling functions out of nowhere, instead of using methods inside classes; All that just seems... wrong!

So finally, is there any reason for me to continue with this massacre to the OOP

Well, calling functions that don't belong to classes isn't OOP -- it's procedural programming. Thus, I believe you're really having a difficult time breaking out of the OOP mindset. (Certainly C++ has many ills, but procedural programming isn't one of them.)

C++ is a multi-paradigm language, not just an OO langage. Templates are a form of generic programming which can be applied to procedural, OOP, and meta-programming paradigms of C++. With the next C++ standard, you'll see some functional paradigms added as well.

All that stuff of putting the class definition in a header file, and the methods in a different source file;

This has its origins from the C programming language, back in the 70's. C++ was designed to be backwards compatible with C.

The D programming language is an attempt to fix many of the ills of C++ (and as I said earlier there are many), but maintain the good features of C++ -- including all the various paradigms C++ supports: procedural, OOP, metaprogramming, and functional.

If you want to break out of the OOP mindset, try D! Then, when you get a feeling for how to mix and match the different paradigms, you can (if you so desire) come back to C++ and learn to deal with its syntax and other ills.

P.S. I use C++ daily and I am a fan of it -- it is my favorite programming language. But as any experienced C++ programmer knows, C++ does have its ills. But once you master the different paradigms and know how to work around C++'s ills, you'll have an incredibly powerful tool (for that is all a language is) at your disposal.

Good luck in your adventures!

Uhall
Agreed. In any case, Java has classes consisting only of static methods (java.lang.Math, for example). Having a fake class as a place-holder doesn't make that any "more OOP" than free functions in C++, and some of them are less powerful than the C++ equivalents because they're not generic.
Steve Jessop
+1  A: 

I think many programmers cut their teeth with MicroSoft products (and their example code) and/or programming for Windows API and the early Microsoft coding conventions which were used in the code fragment in your question (I.e. Hungarian notation, capitalization of defined types, etc..). I loathe looking at source code from MicroSoft which looks like it has been run through a crosscut paper shredder and glued back together. But an ugly coding convention is not a function or reflection of the C++ language which I find no more beautiful or ugly than most other languages.

Actually, I find the C++ syntax with minimal keywords, curly braces and rich set of symbolic operators serves to not distract from or crowd out the important stuff: my variables, my type defs, my methods; which, of course, allows me to make the most beautiful code of all :-)

Roger Nelson
+2  A: 

Separate declaration and definition is the least of the differences between C++ and Java. The major difference in modern C++ is the importance of "value semantics".

Due to the lack of garbage collection but the excellent support for building types that behave like self-contained values, good C++ style involves writing well-behaved value types, with consistent construction, copy-construction, assignment, swap and destruction.

Swap in particular is a very important one to remember because it's not directly supported by the language but it really should be there in any value-like type.

Look at how the standard C++ library works, and how it expects your types to behave.

Try to aim (not always possible) for a total absence of naked pointers or uses of the new operator. Hide such details inside classes that ensure they are used correctly, wrapping them up in value semantics.

Daniel Earwicker
+2  A: 

Like a stereotypical programmer who programs in one specific paradigm, you decided that certain things that aren't familiar with you is just ugly.

C++ is a different language, it's multiparadigm, and it has lots of carry-overs from C. As other have stated, that's just the way it is.

Header files are there for the compiler to check basic syntax without knowing the implementation. If you're a heavy Java programmer, you should be fairly familiar with the whole program to an interface concept. Think of the header file is where the interface is.

If you don't believe me, go look at some Mods out there for games. It's entirely possible to find the CryEngine2's header file somewhere because Crysis mods would need to talk to it, but it doesn't need to understand how it works. The header files will define how ultimately a calling function should setup the stack to call another function.

Not to be condensending, but I think what you really need is to program in something completely different. Research other paradigms, and find some languages, and start writing some toy applications. At first, things would look ugly, but you'll eventually see the advantages.

I said the same thing about functional programming too. Now I complain about how PHP butchered functional programming with arrays.

Calyth