5

I'm trying to emulate a constructor. I'm attempting to do this by having a parent Struct have a function pointer that returns a pointer to a child struct. Any help would be much appreciated.

#include <stdio.h>
#include "stdlib.h"

typedef struct child_t {

  char *name;

} Child;

typedef struct parent_t {

  Child (*NewChild)();

} Parent;

Child *NewChild() {
  Child *child = malloc(sizeof(Child));

  child->name = "foo";

  return child;
}

int 
main()
{
  Parent parent;

  Child child = parent.NewChild();
}
jonathanberi
  • 1,867
  • 1
  • 14
  • 24

3 Answers3

9

It seems like you haven't initialized parent.NewChild. Try setting that to the function pointer before calling it, like this: parent.NewChild = NewChild;.

Also, aren't you missing the * in Child *child = parent.NewChild();?

Addendum: By the comments, there is also an error/conflict in the declaration of Parent: Its NewChild member function is declared to return a Child, while the free method NewChild returns a Child*. So declare the member function pointer as Child * (*NewChild)();.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
anderas
  • 5,744
  • 30
  • 49
  • 2
    And I would point the fact that `child->name = "foo";` is probably not doing what is actually intended. – Eugene Sh. Jul 22 '15 at 15:06
  • BTW, the `&` is not needed. – Eugene Sh. Jul 22 '15 at 15:10
  • @EugeneSh. Thanks, removed it. Is it just not needed or actually wrong?(Haven't done any real C programming for a while, only C++)... – anderas Jul 22 '15 at 15:13
  • 1
    See [here](http://stackoverflow.com/questions/9552663/function-pointers-and-address-of-a-function). Or in the nutshell, it's the same – Eugene Sh. Jul 22 '15 at 15:14
  • Hmm, that doesn't seem to work. I'm getting incompatible types: `incompatible pointer types assigning to 'Child (*)()' from 'Child *(*)()' parent.NewChild = &NewChild;` & 'initializing 'Child *' (aka 'struct child_t *') with an expression of incompatible type 'Child' (aka 'struct child_t') Child *child = parent.NewChild();` – jonathanberi Jul 22 '15 at 15:14
  • 2
    I think it should be `Child* (*NewChild)();` in the `parent` type definition. – Eugene Sh. Jul 22 '15 at 15:17
  • `Child *NewChild()` returns `Child *` but `Child (*NewChild)()` is defined as a function pointer to a function returning `Child`. It should be `Child *(*NewChild)()` – Andrew Henle Jul 22 '15 at 15:20
  • @EugeneSh. - Beat me to it. – Andrew Henle Jul 22 '15 at 15:20
3

I think you mean the following

#include <stdio.h>
#include <stdlib.h>

typedef struct child_t {

  char *name;

} Child;

typedef struct parent_t {

    Child * ( *NewChild )( void );

} Parent;

Child * NewChild( void ) 
{
    Child *child = malloc( sizeof( Child ) );

    child->name = "foo";

    return child;
}

int main( void )
{
    Parent parent = { NewChild };

    Child *child = parent.NewChild();

    puts( child->name );

    free( child );
}    

The program output is

foo

That is you should declare the function correctly. Its return type must be a pointer. So you must to declare the function pointer correctly in the structure definition

typedef struct parent_t {

  Child (*NewChild)();
  ^^^^^^
} Parent;

And you need to initialize the object of type Parent.

Parent parent = { NewChild };

otherwise it has an indeterminate value.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

I see the following problems in your code.

Mismatching function and function pointer

In Parent, you have defined NewChild as:

Child (*NewChild)();

That says NewChild is a pointer to a function that takes no arguments and returns a Child object.

The function that you have defined:

Child *NewChild() { ...

Takes no arguments and returns a pointer to a Child, not an object of Child.

You'll have to decide which one needs to be fixed. To fix the function, make its return type Child.

Child NewChild() { ...

Uninitialized Child of parent

You have left the value of parent.Child uninitialized yet you are trying to use it.

Setting the member of Child

You use the following code to set the name of child.

child->name = "foo";

This may or may not be a problem depending on how you use child->name since child->name points to some global data in the computers read-only memory. It will be better to make a copy of "foo".

Here's my suggestion for updating your code:

Child NewChild() 
{
   Child child;

   // strdup is available on some platforms but it can 
   // be implemented easily.
   child->name = strdup("foo");

   return child;
}

int main()
{
   Parent parent;
   parent.NewChild = NewChild;

   Child child = parent.NewChild();
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270