6
  1. In Java it is very easy to serialize objects. In C++ it is only safe(?) to memcpy objects as long as they are like C structs (no polymorpism). In C++, if the compiler is able to generate the default (trivial) copy constructor then why can't it generate code for automatic serialization?

  2. In Java, only static functions and data members are reachable from the ctor. In C++ I can happily use the non-static members and functions from the ctor.

  3. In Java, I can initialize data members inline, in the class. In C++ it is a compile error.

  4. In Java I can initialize final members in the ctor. In C++ I have to do the initialization of the const members in the initialization list. In C++, when control reaches the body of the ctor, all the members ctor has run, right?

  5. In Java a ctor can call another ctor. In C++ we cannot do that.

  6. In Java, the this is not valid until after the ctor returns (escape of the this reference, a bug in multi-threading). When is this valid in C++? The this can easily escape both in C++ and in Java: registering a not yet constructed object to Listeners in the ctor (observer pattern).

  7. In Java, I cannot make a public function of the base class private in the derived class. I was shocked to see that in C++ is OK and even useful.

Could anyone give a short explanation for these differences?

Update. Trying to collect the answers got so far.

  1. Boost has some serialization-like support. (Tony)

  2. Even though I messed up this point, Alf P. Steinbach gave an interesting example.

  3. C++0x will support much more practical initialization than C++98. (Alf P. Steinbach) #3 will be legal in C++0x (Ken Bloom)

  4. The data members declared in the constructor's own class are guaranteed to have been fully constructed by the time the constructor's {body} starts executing. (c++-faq-lite)

  5. C++0x will allow constructors to call other peer constructors (Wikipedia, C++0x)

  6. C++03 considers an object to be constructed when its constructor finishes executing (Wikipedia).

  7. Things like access control have little to do with the object model: that's a feature of the access control system which is a compile time feature. (Yttrill)

11
  • No, it's not even safe to memcpy them then. (Also, a ctor can call another ctor in C++0x). Commented Dec 10, 2010 at 2:18
  • 2
    Oh, and Java doesn't have ctors--they have constructors. In Java they prefer to spell everything out rather than use cryptic abbreviations--another philosophy difference. Commented Dec 10, 2010 at 2:27
  • 3
    @Bill K: C++ prefers to spell everything out too. (i.e. std::set_symmetric_difference or std::lexicographical_compare). It's more common to see shortened names in C because C specifies that linker names are only required to be differentiated by the first 8 characters. Commented Dec 10, 2010 at 2:32
  • #2 for Java is wrong, I can happily call methods on my object from its constructor. #6 is also wrong for Java, it is perfectly legal to allow the this reference to escape to another Thread inside the constructor. Of course, allowing the this reference to escape is rather inadvisable. Commented Dec 10, 2010 at 2:39
  • #2 and #4 contradict each other (hint: #2 is wrong) Commented Dec 10, 2010 at 2:40

6 Answers 6

4

In Java it is very easy to serialize objects. In C++ it is only safe(?) to memcpy objects as long as they are like C structs (no polymorpism).

Java is an interpreted language (or more recently, as Billy comments, JIT compiled), so it has no choice but to carry around metadata baggage of every data type in the program at run time. Between the interpreter, VM, optional compiler and metadata overheads, Java programs need a lot of memory. C++ is a compiled language, where many of the decision Java makes are made once at compile time, and the metadata isn't around for interpretation to guide serialisation at run-time. In general, the metadata isn't exposed even at compile time, probably because different compiler vendors model the program quite differently, and they haven't collectively negotiated a suitable representation. It's also considerable work. Bjarne Stroustrup has some papers on how to expose such information, but it's not even planned for C++0x. Meanwhile, with a little manual markup C++ programs can serialise objects - see boost for a good implementation.

In Java, I can initialize data members inline, in the class. In C++ it is a compile error.

Each C++ constructor provides a complete, independent view of how the object will be initialised. If worthwhile, common construction steps can be factored into a support routine, but the call to that is still visible in the constructor. Having to inspect various assignments scattered through the class would delocalise that, though it can certainly be convenient. Much of a muchness here, I'd hazard.

In Java I can initialize final members in the ctor. In C++ I have to do the initialization of the const members in the initialization list.

This reflects the idea that const members are created with their one and only value, and do not transition from some indeterminate or null state to an initialised state.

In Java a ctor can call another ctor. In C++ we cannot do that.

Yes, it's a little annoying in C++ sometimes - particularly for references and consts that need to be in the initialiser list, but you can factor other common construction steps into a support function. I think C++'s position reflects the job of a constructor in constructing bases, members, pointers to virtual dispatch tables etc. - it's not necessarily possible at the machine code level to call into one constructor from another and have just the right steps execute. The compiler could be required to generate a second callable-from-another-constructor version, or inline the right parts of the called constructor, but that's kind of hidden bloat.

In Java, I cannot make a public function of the base class private in the derived class. I was shocked to see that in C++ is OK and even useful.

Given you acknowledge it's useful, maybe Java should add it.

Could anyone give a short explanation for these differences?

Well, I tried.

Sign up to request clarification or add additional context in comments.

4 Comments

"Given you acknowledge it's useful, maybe Java should add it." <- I don't think "it's useful" has ever been an important design criteria for Java. "It's simple", sure, or "It's OOP" or "it's impossible to screw up". But I can't think of a single feature that was added because "it's useful" ;)
Java bytecode may require a VM to run, but Java is still compiled. As your answer suggests, what C++ compiles to isn't specified, while what Java compiles to is, which is why object metadata is available in Java.
I should have said usually compiled. There's always BeanShell.
Java bytecode is typically JIT compiled, not interpreted. The days of Java being interpreted are long gone.
4

Many of these are covered by design philosophy.

In a lot of cases, Java disallowed practices that were dangerous or didn't make sense most of the time. For instance, you cannot call a method from a constructor because there is no guarantee that the members have been initialized until the constructor exits. Java tries not to let any reference to an object escape until the constructor has completed.

In C++ they generally assume the programmer knows all the potential ramifications of his actions and lets them do whatever they want.

Also Java threw away C backwards compatibility, you can't take a C file and hand it to a Java compiler.

The rest of the differences are probably just cases where C++ was designed before Java and Java learned some stuff from problems people had with C++. The same way C# has cleaner syntax or more functionality than Java in some cases, because they learned from Java.

5 Comments

I always thought of it as "C/C++ will take any string of characters and try hard to find some way to interpret it to be a valid expression. After all, if the programmer wrote it, it must be right ...". On the other hand, my friend loves to remind me that "C/C++ is for real men - Java makes you weak ..."
Java 1.0 was released in 1995 or so. C++ was standardized in late 1998. I don't think you can just conclude that "Java learned from C++". It worked both ways. In designing Java they obviously looked at early pre-standard C++, and likewise, leading up to the standardization of C++, they equally obviously looked at, and learned from, many of Java's mistakes. (it's interesting to note that a lot of what happened in the last few years before standardization was a reduced emphasis on OOP. Perhaps Java ended up serving as a warning? ;))
Java was able to rewrite many things C++ couldn't because of compatibility--in other words, C++ was, in many cases, prevented from learning. For instance--weather you agree with it or not--how could you eliminate pointers and still call it C++? C++ was in fairly wide use while Java was being developed so Java did take a lot of lessons from C++.
@Bert F and assembly programmers will tell you that C makes you weak, and C programmers will tell you that C++ makes you weak. Yeah, they all target different spaces and are all valid for their spaces. Many of the things I do in Java would be a nightmare in C++, and many solutions can be optimized much better in C than Java (especially where memory is concerned).
Err.. how does "elimination of pointers" mean learning? If anything, C++ emphasizes use of pointers (or pointer like objects... i.e. the STL). Anyway, comparing C++ and Java is a bit like comparing apples and oranges. Both are general purpose programming languages, but C++ is geared much more toward systems programming, something you'd never want to touch with Java with a 10 foot pole.
3

They're different languages. <- how's that for short.

Comments

3

The OP's title is a bit confused. Things like access control have little to do with the object model: that's a feature of the access control system which is a compile time feature. The sequencing of object construction is part of the object model. The key difference between C++ and Java is actually that Java is garbage collected, whereas C++ is not.

Another core differences is that Java uses archaic crud for polymorphism, whereas C++ uses a broken template concept: in C++ templates are compile time and don't impact the object model, in Java polymorphism is hacked around what in C++ is called a dynamic cast.

Another major core difference is that Java supports threads whereas in C++ you have to use a library of some kind.

There are lower level type system differences too: Java has minimal static typing but otherwise is basically a dynamic language. C++ on the other hand is almost entirely a statically typed language, with the exception of exceptions ..:)

Comments

2

A bit of Java:

class Base
{
    public static void say( String s )
    {
        System.out.println( s );
    }

    public void sayHello()
    {
        say( "Base.sayHello says..." );
        say( "Base hello" );
    }

    public Base()
    {
        sayHello();
    }
}

class Derived
    extends Base
{
    private String[] myWords;   // = new String[]{ "Derived", "hello" };

    public void sayHello()
    {
        say( "Derived.sayHello says..." );
        say( myWords[0] + " " + myWords[1] );
    }

    Derived()
    {
        myWords = new String[]{ "Derived", "hello" };
    }
}

class ConsCallDemo
{
    public static void main( String[] args )
    {
        Derived o = new Derived();
    }
}

Output:

Derived.sayHello says...
Exception in thread "main" java.lang.NullPointerException
        at Derived.sayHello(conscall.java:28)
        at Base.(conscall.java:16)
        at Derived.(conscall.java:32)
        at ConsCallDemo.main(conscall.java:41)

The problem is that in Java the calls go down to the class that the object is instantiated from, even before that instance has been initialized.

C++ guards against this problem by dynamically adjusting the type of the object during construction and destruction. In C++ the object is of type Base when the Base constructor executes. Thus, calls from within the Base constructor behave is if the object was instantiated from class Base, regardless of actual instantiation class.

Example of that, just translating the Java code above to C++:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void say( string const& s )
{
    cout << s << endl;
}

class Base
{
public:
    virtual void sayHello() const
    {
        say( "Base::sayHello says..." );
        say( "Base hello" );
    }

    Base()
    {
        sayHello();
    }
};

class Derived
    : Base
{
private:
    vector< string >    words_;

public:
    void sayHello() const
    {
        say( "Derived::sayHello says..." );
        say( words_[0] + " " + words_[1] );
    }

    Derived()
    {
        words_.push_back( "Derived" );
        words_.push_back( "hello" );
    }
};

int main()
{
    Derived o;
}

Output:

Base::sayHello says...
Base hello

One way to obtain the probably intended effect in C++, which also suggests how to do it (properly) in Java:

#include <iostream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
using namespace std;

void say( string const& s )
{
    cout << s << endl;
}

class Base
{
protected:
    struct Greeter
    {
        typedef boost::shared_ptr< Greeter >    Ptr;

        virtual void sayHello() const
        {
            say( "Base::sayHello says..." );
            say( "Base hello" );
        }
    };

private:
    Greeter::Ptr    greeter_;

public:
    void sayHello() const
    {
        greeter_->sayHello();
    }

    Base( Greeter::Ptr greeter = Greeter::Ptr( new Greeter ) )
        : greeter_( greeter )
    {
        sayHello();
    }
};

class Derived
    : Base
{
protected:
    struct Greeter
        : Base::Greeter
    {
        vector< string >    words_;

        virtual void sayHello() const
        {
            say( "Derived::sayHello says..." );
            say( words_[0] + " " + words_[1] );
        }

        Greeter()
        {
            words_.push_back( "Derived" );
            words_.push_back( "hello" );
        }
    };

public:
    Derived()
        : Base( Greeter::Ptr( new Greeter ) )
    {}
};

int main()
{
    Derived o;
}

Output:

Derived::sayHello says...
Derived hello

Regarding your other points, it's too much to discuss here. Just be aware that C++0x will support much more practical initialization than C++98. And also that the formal side of your point 7 is a bit contested, there's a Defect Report about it (it was not allowed in pre-standard C++ as described by the Annotated Reference Manual, but it was apparently intended to be allowed in standard C98, however, the wording is a bit self-contradictory).

Cheers & hth.,

Comments

1

About 7:

In Java, I cannot make a public function of the base class private in the derived class. I was shocked to see that in C++ is OK and even useful.

If you were able to hide a superclass method that would not guarantee your method can not be called by a user. One could always cast to the superclass and call the method, since all non-static methods in Java are as C++ virtual methods your subclass method would actually be called.

It would work with static methods but I don't think overriding static methods is a good practice.

The need to hide methods in subclasses usually means bad design, but if you really need to, you should throw an exception. The down side of this is that it's runtime, but when a call occurs it WILL crash. Whereas in C++, if you hide a method but cast to the parent class, if its virtual the method will actually get called and if it's statically linked the parent class method will get called, both are probably not what you want.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.