2

Let's say I have two custom classes in Java, class A and class B:

class A {
    int x;
    int y;
    public A(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

class B {
    A a;
    int z;
    public B(A a, int z) 
    {
        this.a = a;
        this.z = z;
    }
}

And I want to translate this situation into C++.

class A will translate more or less as it is, but when I go to class B and write such code:

class B {
    A a;
    int z;
    public:
    B(A a1, int z1){
        a = a1;
        z =z1;
    }  
};

it complains saying that class A does not have default constructor, so when I declare A a; at the top of class B it cannot instantiate my "a" variable (Java does not instantiate at declaration, whereas C++ does, as I understand).

So what would be the normal C++ way to deal with this situation: should I add default constructor without arguments to class A, or this is not the right way to go?

Thanks a lot.

nanofarad
  • 40,330
  • 4
  • 86
  • 117
user3930976
  • 161
  • 7

4 Answers4

6

Translating from Java to C++ is very sensitive to context. They are really very different languages and it depends heavily on what you are trying to achieve.

In Java user defined types are all accessed via references. The functional equivalent in C++ is a pointer. However in C++ you can access objects directly like built in types. So you could write this:

class A {
    int x;
    int y;

public:
    // note: we don't initialize members in the body
    A(int x, int y): x(x), y(y) {}
};

class B {
    A a;
    int z;

public:
    B(A a, int z): a(a), z(z) {}
};

C++ gives you many more options how to refer to your user defined types and so it really depends on the larger problem you need to solve.

Some other possibilities:

std::shared_ptr<A> a; // much more Java-like (slower)
std::unique_ptr<A> a; // when you need one copy only (more common)
A* a; // when you need to live dangerously
A a; // use it more like a built-in

References:

std::unique_ptr when you only need to manage one

std::shared_ptr when the object needs to be managed from multiple places

NOTE: The difference between how you use Java and how you use C++ are so large that I would recommend forgetting about Java while you are dealing with C++. Learn C++ independently as a new language without constantly referring to the "Java way" of doing things.

Recommended books: The Definitive C++ Book Guide and List

Galik
  • 47,303
  • 4
  • 80
  • 117
  • +1. So far the only answer which correctly considers the big picture and does not only mention smart pointers but correctly avoids to present them as perfect solutions to every problem. – Christian Hackl Mar 21 '15 at 21:15
  • And if I just add a default no argument constructor to A, will that be a big problem? – user3930976 Mar 21 '15 at 21:36
  • @user3930976: It depends. If an `A` can be constructed in a *meaningful* way with zero start information, then no. Otherwise, yes. Default constructors that create "half-complete" objects are a big problem. – Christian Hackl Mar 21 '15 at 21:56
2

in class B initialise instance of class A in initialisation list like so B(A a1, int z1):a(a1) {...} This is required as instance of class A inside class B will be initialised before executing constructor body with default constructor, You have defined Your own constructor for A so there is no default constructor anymore. You can also initialise z1 variable the same way, like this: B(A a1, int z1):a(a1),z(z1){...}

riodoro1
  • 1,246
  • 7
  • 14
  • Can you expand on this answer a bit? What does the syntax mean? Why does it work? – nanofarad Mar 21 '15 at 20:43
  • When You try to make instance of class B in Your code first thing to do is initialising all of the classes members, if there is no default constructor for class A (and there isn't as You defined Your own constructor) the compiler does not know what to do with memeber a. The initialisation list however is executed before executing the constructor itself so You can use any constructor for member of type A there. You can also define default constructor for A and leave anything as is: `A::A():x(0),y(0){}` (with initialisation list) which works like `A::A(){x=0;y=0}` – riodoro1 Mar 21 '15 at 20:51
2

In Java, a declaration like:

A a;

means that you want a reference that can point to an object of type A. You eventually set it with something like:

a = new A(x, y, z);

In C++ the nearest simple thing is a pointer:

A* a;

When you write:

A a;

in C++, you are asking the compiler to make a local object, right here. So you have to supply all the constructor args. That's not what your Java code is doing, so you don't want it in C++ if what you are doing is a line-by-line, straight, port. (Hint: you would be better off writing yourself an explanation of what the program does and then creating a Java implementation in idiomatic Java from scratch.)

If you are trying to map from Java to C++, which is a very dangerous process, every declaration like:

A a;

has to map to either:

A* a;

or

A& a ... /* some initialization, unless a parameter or member. */

and you have to worry about all the storage allocation for yourself.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • 1
    *"That's not what you Java code is doing, so you don't want it in C++."* -- Why not? In C++ we do things differently. In Java, every object variable is a reference because there is no other choice. That doesn't mean that, when translating the code to C++, you have to make every object variable a pointer. We translate the code to use the idioms that are appropriate to C++. – Benjamin Lindley Mar 21 '15 at 20:51
  • Why do you think it will work to radically change the lifetime of the A object from outside his function to inside? – bmargulies Mar 21 '15 at 20:53
  • I have no idea whether it will or won't. It depends upon how the class is used. You've corrected your statement though, so the point is now moot. – Benjamin Lindley Mar 21 '15 at 21:00
  • `A& a;` is an illegal declaration. – Emil Laine Mar 21 '15 at 21:02
  • @zenith: Not as a class member. – Benjamin Lindley Mar 21 '15 at 21:03
0

a = a1; is not an initialization of a. It's an assignment. a was already initialized before that statement (or would've been if it had a default constructor, hence the error).

In C++, each member variable is initialized before entering the constructor body. You have to use the member initialization list if you want to initialize a with a1:

B(A a1, int z1) : a(a1), z(z1) { /* constructor body */ }

This will simply initialize a with a1 and z with z1, and is the way to do it in C++.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157