views:

125

answers:

8

I'm moving from Java to C++ right now and I'm having some difficulties whenever a commonly used concept in Java doesn't map directly into C++. For instance, in Java I would do something like:

Fruit GetFruit(String fruitName) {
    Fruit fruit;
    if(fruitName == "apple") fruit = new Fruit("apple");
    else if(fruitName == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat"); //'cause who really wants to eat a kumquat?

    return fruit;
}

Of course, in C++ the Fruit fruit; statement actually creates a fruit. Does this mean I have to have a default constructor? This seems unsafe! What if my default fruit escaped?

+1  A: 

To map your example to C++, you should use a pointer. In C++, an object built is considered a valid object (therefore, with reference, you cannot have null).

Using Fruit* fruit = 0; ...

you can have an object defaulted to your need, or 0 defaulted if no test pass.

Scharron
Would the pointer approach be pretty standard? Or is it weird for some reason?
John Berryman
@John: The pointer approach is standard. It may look weird to a Java programmer, but then again there's things in Java that look weird to a C++ programmer. If you're going to use C++, you need to use pointers of some sort.
David Thornley
it's not bad, but you should take care to delete the pointer afterwards.Or you can use a smart pointer (it's a pointer that counts references and delete itself when noone use it anymore).
Scharron
Owen S.
@Owen S: pointers are common in C. In modern C++ they are very rare and only ever seen wrapped inside an object or when using a C interface. DON'T use a pointer. pointers are bad as they have zero ownership semantics associated with them and thus it is not clear who the owner of the object is. Use a smart pointer (a shared pointer is basically the equivalent of the Java object)
Martin York
@Martin: There is a _lot_ of non-"modern C++" (who came up with that moniker anyway?) out there, and use of raw pointers is frequent enough among both modern and non-modern codebases to qualify as standard. There are also places where smart pointers are not the right solution. And you can still represent "optional" values with null smart pointers, for many classes of smart pointers. Other than that, I agree with you. :-)
Owen S.
@Ownen S: Sorry but I have to disagree with you. In old C code and code that I would class "C with classes" pointers are common. But in C++ code where exceptions are a rule and RAII is the norm pointers are quite literally non existentant (The only time I have seen a pointer in production code for 5 years is when it is the sole member of a wrapper class that manages the pointer). Its OK for the hobyist and beginners but working in large teams and building professional re-usable libraries it just does not work. Switch to smart pointers.
Martin York
A: 

Your fruit variable in java roughly maps to a C++ pointer. You're correct, you don't want to create the object on the stack, you just want a pointer to the new object that you're creating. So if you just change Fruit to Fruit* this will work (if you change the function return type as well). Just remember that you must later delete the pointer you returned from this function, there's no garbage collection to cleanup your news.

bshields
+4  A: 

Objects in Java are represented by pointers. Since this is pervasive, there is no special notation for pointers. In C++, objects can be represented by themselves or by pointers, so it's necessary to specify pointers when they occur.

The C++ version of your code is:

Fruit * GetFruit(std::string fruitName) {
    Fruit * fruit = 0;
    if (fruitname == "apple") fruit = new Fruit("apple");
    else if (fruitname == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat");

    return fruit;
}

This returns a pointer to Fruit. You would access members like fruit->color(), not fruit.color(). You should delete that pointer when you're through with it.

David Thornley
Object in java. Are the equivalent of shared pointers. Returning a pointer is a sign of code smell or C code (the same thing to me. :-)
Martin York
A: 

Default constructor - No, the compiler creates a default one for you, if you don't write one.

You can write explicit constructors to invoke only specific constructors which you require.

And implement your destructor to clear up whatever memory allocation stuff you do in your constructor. Or best use the boost smart_ptr library.

DumbCoder
+2  A: 

The most straightforward way would be:

Fruit GetFruit(String fruitName) {
    if(fruitName == "apple") return Fruit("apple");
    else if(fruitName == "banana") return Fruit("banana");
    else fruit = return Fruit("kumquat"); //'cause who really wants to eat a kumquat?
}

... and a direct mapping would be to use a (preferably "smart") pointer:

auto_ptr<Fruit> GetFruit(String fruitName) {
    auto_ptr<Fruit> fruit;
    if(fruitName == "apple") fruit = new Fruit("apple");
    else if(fruitName == "banana") fruit = new Fruit("banana");
    else fruit = new Fruit("kumquat"); //'cause who really wants to eat a kumquat?
    return fruit;
}
Éric Malenfant
A direct mapping is quite hard since Java uses nondeterministic garbage collection, whereas `auto_ptr` uses transfer-of-ownership semantics and raw pointers use no memory management at all. A variant that might be a bit less surprising is a reference-counted pointer such as `shared_ptr`.
Philipp
+5  A: 

C++ gives you much more headache when it comes to creating fruits. Depending on your needs, you can choose one of the following options:

1) create a Fruit on a stack and return a copy (you need a copy constructor) then and must provide some default fruit in case the name does not match:

Fruit GetFruit(const std::string &name)
{
   if ( name == "banana" ) return Fruit("banana");
   if ( name == "apple" )  return Fruit("apple");
   return Fruit("default");
}

2) create a Fruit on a heap and take care, that there could be null-pointer returned and also remember to delete this fruit somewhere and take care that it is deleted only once and only by its owner (and take care that noone holds a pointer to the deleted fruit):

Fruit* GetFruit(const std::string &name)
{
   if ( name == "banana" ) return new Fruit("banana");
   if ( name == "apple" )  return new Fruit("apple");
   return NULL;
}

3) and finally, use a smart pointer to avoid many possible pointer problems (but take care of null pointers). This option is the closest to your Java programming experience:

typedef boost::shared_ptr<Fruit> FruitRef;

FruitRef GetFruit(const std::string &name)
{
   if ( name == "banana" ) return new Fruit("banana");
   if ( name == "apple" )  return new Fruit("apple");
   return FruitRef();
}
SadSido
+1 for number 3, shared_ptr is the answer, your complier probably has an implementation without boost as shared_ptrs are in tr1
Patrick
4. Use `boost::optional<Fruit>` if you'd rather avoid dynamic allocation.
Mike Seymour
@Mike Seymour. Never heard of boost::optional. Thanks for your comment =)
SadSido
+1  A: 

In C++ there are pointers, which are implicit in Java: there is a difference between an object (that is an entity in memory) and his address. In Java, you need to explicitly create an object, because when you write

MyClass name;

you're creating a reference for an object of that class. This means that name identifies a small memory location which contains the real object address. When you build the whole house using new, it returns only the address, which is assigned to that small memory location.

In C++ there is a better control of memory and you have 2 ways of creating an object: if you use the statement

MyClass object;

This object is created in the stack. This means that when the function returns, the object is destroyed. Note that the object is automatically created, without using the new operator. If you want an object to persist the stack destruction, you shall use the new operator, which returns a pointer to the newly created object:

MyClass *objectPtr = new MyClass();

The * placed after the class name, means you're asking for the relative pointer type instead of an allocation of that object.

Remember you have to clean the memory when you don't need the object anymore, or there will be a memory leak:

delete objectPtr;

So, you can do like this:

MyClass *yourfunction(bool param) {
    if (param)
        return new MyClass(A);
    return new MyClass(B);
}

You shall know, anyway, that Pointers aren't safe at all! Giving the user control over pointers can lead to bad code, bad practices and lot of things that aren't good at all Immediate example: what if you forget to clean the memory after object usage?)

In this case, it's better if you use smart pointers, but now there is really too much to say :) Enjoy googling!

HIH

AkiRoss
A: 

Objects work somewhat differently in Java vs in C++. As you noted, in your code you would default create an object and then you run the risk of it being passed around later. To make the minimum amount of change to your code:

Fruit GetFruit(std::string fruitName) {
    if(fruitName != "apple" && fruitName != "banana")
    {
        fruitName = "kumquat";
    }
    return Fruit(fruitName);
}

However this code will result in the object itself (including all of its internal data) being copied in the return, as well as if its copied around in further use.

To be more Java-esque you would use a boost::shared_ptr instead. Then you're dealing with a reference counted object, just like in Java:

boost::shared_ptr<Fruit> GetFruit(std::string fruitName) {
    if(fruitName != "apple" && fruitName != "banana")
    {
        fruitName = "kumquat";
    }
    return new Fruit(fruitName);
}
Mark B