godfatherofpolka
godfatherofpolka

Reputation: 1683

Initialization of members when inheriting from extern C struct

In Mixing C and C++ Code in the Same Program the following example (slightly abbreviated here to the relevant parts) is given. Assume buf.h contains the following:

struct buf {
    char* data;
    unsigned count;
};

// some declarations of existing C functions for handling buf...

It is then recommended to use

extern "C" {
  #include "buf.h"
}

class mybuf : public buf {
public:
    mybuf() : data(0), count(0) { }

    // add new methods here (e.g. wrappers for existing C functions)...
};

in order to use the struct within C++ with added features.

However, this clearly will produce the following error:

error: class `mybuf' does not have any field named `data'
error: class `mybuf' does not have any field named `count'

The reasons for this are explained in How can I initialize base class member variables in derived class constructor?, C++: Initialization of inherited field, and Initialize parent's protected members with initialization list (C++).

Thus, I have the following two questions:

  1. Is the code provided just plainly wrong or am I missing some relevant aspect? (After all, the article seems to stem from a reputable source)
  2. What is the correct way to achieve the desired effect (i.e., turning a C struct into a C++ class and adding some convenience methods like, e.g., a constructor, etc.)?

Update: Using aggregation initialization as suggested, i.e.,

mybuf() : buf{0, 0} {}

works, but requires C++11. I therefore add the following question:

  1. Using C++03, is there a better way to achieve the desired outcome than using the following constructor?

    mybuf() {
      data = 0;
      count = 0;
    }
    

Upvotes: 17

Views: 1658

Answers (4)

Simon Gibbons
Simon Gibbons

Reputation: 7194

If you can use a c++11 compatible compiler then this would be a perfect use case for an initializer list using aggregate initialization.

mybuf() : buf{0, 0}
{}

Upvotes: 8

Peter
Peter

Reputation: 36617

class mybuf : public buf {
public:
    mybuf();    
    // add new methods here (e.g. wrappers for existing C functions)...
};

const buf init = {0,0};

mybuf::mybuf() : buf(init) {};

will work.

I have seen this work with some compilers, but don't have a standard handy to check if it is standard or an extension.

class mybuf : public buf {
public:
    mybuf() : buf(init) { }

    // add new methods here (e.g. wrappers for existing C functions)...

    private:

    const buf init = {0,0};
};

Upvotes: 2

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385295

This has nothing to do with mixing C and C++. You're trying to initialise members that don't exist; that they exist in a base class isn't enough. You need to initialise the base itself.

In this case, use aggregate initialisation:

class mybuf : public buf
{
public:
    mybuf() : buf{0, 0} {}
};

Upvotes: 3

Some programmer dude
Some programmer dude

Reputation: 409384

One "correct" way, if your compiler is C++11 capable, is to use e.g.

mybuf() : buf{0, 0} {}

Upvotes: 3

Related Questions