views:

173

answers:

5

If it is, what is it supposed to do?

typedef struct Foo_struct{
  Dog d;
  Cat* c;
  struct Foo_struct(Dog dog, Cat* cat){ this->d = dog; this->c = cat;}
} Foo;

(back story: porting a program written in Visual C++ (on Windows) to g++ (on MacOSX); no idea what this code is suppoesd to do).

Thanks!

A: 

It looks like it defines a structure called Foo_Struct, which holds an instance of Dog, have a pointer to a cat, and have a constructor which takes in an instance of Dog, pointer to Cat, and assign them to itself.

Then creates an instance of Foo on the stack.

Edit: I'm not sure whether that third line is a constructor or something else.

Extrakun
+3  A: 

It's almost legal but has one error. A struct is just like a class except the default protection is public instead of private.

Okay, let's break it down:

// The next line is defining a struct called "Foo_struct", it's also
// saying it's going to give an alternate type name (that's the typedef).
// The alternate type name comes after the definition.
typedef struct Foo_struct{

  // The structure has a Dog element (this means we need to have seen
  // the definition of Dog already).
  Dog d;

  // And has a pointer to cat (this means we need to have at least seen
  // a declaration of Cat) 
  Cat* c;

  // Okay, this is definining a constructor.  The constructor must be
  // called with a Dog object and a pointer to a cat which the constructor
  // will save in the object.
  //
  // Here is the one error.  That 'struct' at the start shouldn't
  // be there (commenting out to make the code legal).
  /* struct */ Foo_struct(Dog dog, Cat* cat){ this->d = dog; this->c = cat;}

// And here we close out the struct and also finish off the typedef
// started on the first line.
} Foo;
R Samuel Klatchko
@Samual: I'd change the text now reading "...is creating a struct called..." to "...is creating a struct _type_ called...". At least around where I live (non-native English speakers) "creating a struct" would be understood as creating an _object_ of the struct's type, not as creating a struct type. That might just be us non-natives here, though. +1 anyway, since you're right otherwise.
sbi
@sbi - thanks for the feedback; I changed it to "is defining a struct called".
R Samuel Klatchko
+8  A: 

I don't think it is. (And Comeau agrees with me.) You cannot define a constructor like this.

In C++, struct names are first-class citizens. There's no need to employ the old typedef trick from C. Also, d and c should be initialized in a member initialization list. This would be valid (and better (C++):

struct Foo {
  Dog d;
  Cat* c;
  Foo(Dog dog, Cat* cat) : d(dog), c(cat) {}
};

The code defines a struct (in C++, the same as a class, except that its members are public by default) with a constructor to initialize its members upon creation.

Edit: As Travis said in his comment, you might want to consider passing dog as a const reference instead of copying it:

Foo(const Dog& dog, Cat* cat) : d(dog), c(cat) {}

If Dog (which we haven't seen) is a class with more than one built-in member, this might be considerably cheaper than passing it per copy.

sbi
Travis Gockel
@Travis: I was changing the code to do so while you added your comment. `:)`
sbi
@Travis - Baby steps. :)
Chris Lutz
@sbi: I disagree with the edit. Since `dog` is going to get copied anyway it could actually be cheaper to pass it by value because of the optimizations the compiler might do (if the method is not inlined). At any rate, it should not be more expensive because of all the copy elisions tricks the compiler get up its sleeve.
Matthieu M.
@Matthieu: I see this a lot since rvlaue references are discussed. But so far we don't have them yet and I cannot see any circumstances when passing an object per `const` reference would be more expensive than passing it per copy. Relying on compilers to eliminate the copy is all well and good - but since this isn't reliable in the absence of rvalue references, I will prefer passing per `const` reference until proven wrong by a profiler. See also http://stackoverflow.com/questions/2139224/2139254#2139254.
sbi
Matthieu M.
+5  A: 

No it's not. You cannot have the struct in the constructor. A valid C++ code with minimal change would be

typedef struct Foo_struct{
  Dog d;
  Cat* c;
  Foo_struct(Dog dog, Cat* cat){ this->d = dog; this->c = cat;}  // <-- remove the "struct"
} Foo;

For a better approach see @sbi's answer.

KennyTM
+4  A: 

Mostly, though the struct and typedef are unnecessary. Better written in C++ as:

class Foo {
  public:
    Foo(Dog dog, Cat *cat) : d(dog), c(cat) {}
  private:
    Dog d;
    Cat *c;
};

Line-by-line:

class Foo {

The same as struct Foo. The only difference in C++ between a class and a struct is that a struct's members are public by default, while a class's members are private. But we need some public members somewhere, so we get around that with...

  public:

Everything after this is public, and can be accessed by anyone with a Foo object.

    Foo(Dog dog, Cat *cat) : d(dog), c(cat) {}

This is the constructor for Foo. It makes a new Foo object, given a Dog and a Cat *. The : d(dog), c(cat) is an initializer list. It is the same as this->d = dog; this->c = cat; except probably faster. If you didn't want to do it that way, you could leave off the this-> unless there was a naming conflict somewhere. The {} is the function body, empty because we moved the assignment to the initializer list.

  private:

Opposite of public:. Things declared after this can only be accessed inside our class, and are for internal use only.

    Dog d;
    Cat *c;

These are the class's internal variables, like the members of a struct.

Chris Lutz
`class` is not exactly the same as `struct` since `class` defaults to private visibility.
KennyTM