3

I have a GObject "A" which creates an instance of another GObject "B" in its constructor.

The "B" object needs to be passed several construction-only properties. Now when creating an instance of object "A" I want to allow passing values for these properties through the constructor of object "A" on to the constructor of object "B".

The only way I have found to do that was to create identical properties for object "A" and pass their values on to the constructor of "B". These properties would have no further meaning to "A" so this seems like a kludge.

Is there a better way to do what I want?

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113
user996839
  • 33
  • 3

2 Answers2

1

Use dependency injection, pass an already initialized object of type B to the constructor of A.

That way the client that is using your class can decide whether to pass in different kinds of Bs (if it makes sense you can even use an interface instead of a class as the B type, writing code against interfaces is generally better than writing code against implementations).

Deriving A from B only makes sense if it really is a specialization of it's parent class.

From the question it isn't clear if derivation makes sense, but it's an often overused method for composition.

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113
1
  • Have A inherit from B. Then A has all of B's properties automatically.
  • Don't use properties in A, but instead pass B's properties (or even better, an already-constructed B object) as parameters to A's constructor.
  • Delay construction of B until A can figure out how it nees to configure B. Add a private flag to A, b_initialized or something, that tells you whether A's internal pointer to B is valid.

Some more clarification on the second suggestion:

A's stuff is constructed in the a_init() function that is provided for by the G_DEFINE_TYPE() macro. But that's not how you get an instance of A. It's usual to write a function, which is part of the public interface of A, like this:

A *a_new() 
{
    return (A *)g_object_new(TYPE_A, NULL);
}

You can easily extend this to include other parameters:

A *a_new(int b_param_1, int b_param_2)
{
    A *a = (A *)g_object_new(TYPE_A, NULL);
    a->priv->b = b_new(b_param_1, b_param_2);
    return a;
}

This has the disadvantage of leaving your A object in an invalid state (i.e., without a B) if you construct it using g_object_new, for example if you're trying to build it from a GtkBuilder file. If that's a problem, I still strongly suggest refactoring.

ptomato
  • 56,175
  • 13
  • 112
  • 165
  • Unfortunately both are entirely unrelated and that would "pollute" object "A" even more than just using properties. – user996839 Oct 15 '11 at 16:54
  • Sounds like a prime candidate for refactoring to me. However, I'll add a few more suggestions that I've thought of... – ptomato Oct 16 '11 at 07:19
  • Passing non-property arguments to A's constructor seems to fit what I'm interested in. Do you have any pointer/example on how to do that? – user996839 Oct 16 '11 at 12:59
  • Yes, but it requires delaying `B`'s initialization until after you actually create the `A` object. I'll add some tips to my answer. – ptomato Oct 17 '11 at 08:55
  • Thanks, I wasn't quite sure what you meant before. Basically this is what Vala does as well. Since I'm not building a widget the limit of being forced to use the _new function are not a problem. – user996839 Oct 17 '11 at 09:32