Инициализация на членове при наследяване от extern C struct

В Смесване на C и C++ код в една и съща програма даден е следният пример (леко съкратен тук до съответните части). Да приемем, че buf.h съдържа следното:

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

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

След това се препоръчва да се използва

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)...
};

за да използвате структурата в C++ с добавени функции.

Това обаче очевидно ще доведе до следната грешка:

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

Причините за това са обяснени в Как мога ли да инициализирам променливи на член на базов клас в конструктор на производен клас?, C++: Инициализация на наследени поле и Инициализиране на защитените членове на родителя със списък за инициализация (C++ ).

И така, имам следните два въпроса:

  1. Предоставеният код просто грешен ли е или пропускам някакъв подходящ аспект? (В края на краищата статията изглежда произлиза от уважаван източник)
  2. Какъв е правилният начин за постигане на желания ефект (т.е. превръщане на C структура в C++ клас и добавяне на някои удобни методи, като например конструктор и т.н.)?

Актуализация: Използване на инициализация на агрегиране, както е предложено, т.е.

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

работи, но изисква C++11. Затова добавям следния въпрос:

  1. Използвайки C++03, има ли по-добър начин за постигане на желания резултат от използването на следния конструктор?

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

person godfatherofpolka    schedule 20.04.2015    source източник
comment
Изглежда като копиране и поставяне на грешка. По-рано на същата страница авторът имплементира клас mybuf с data и count членове.   -  person dyp    schedule 20.04.2015
comment
защо поставяте extern C около структурата си? няма нужда.   -  person AndersK    schedule 20.04.2015
comment
@CyberSpock Вижте оригиналния източник на кода, става дума за смесване на C и C++ код и заглавният файл съдържа някои декларации на функции, редактирах кода по-горе, за да стане ясно.   -  person godfatherofpolka    schedule 20.04.2015
comment
@godfatherofpolka структурата е структура, независимо дали е C или C++. няма причина да го увивате във външен C блок. Вашият въпрос не е за смесване на C-C++, а за инициализиране на членски променливи в базовия клас.   -  person AndersK    schedule 21.04.2015
comment
@CyberSpock Да, прав си, extern C не е от значение за проблема, но го запазих там, за да осигуря някакъв контекст на въпроса, по-специално, за да подчертая, че структурата е дадена като чиста C структура и по този начин инициализацията може не се случи на ниво структура (което би било очевидният отговор, в случай че беше C++ структура).   -  person godfatherofpolka    schedule 21.04.2015
comment
@godfatherofpolka лично аз бих направил композиция вместо това, тогава ще бъде по-самостоятелно, където екземплярът на класа може да поеме собственост върху съдържанието на buf. Но зависи как искате да го използвате.   -  person AndersK    schedule 21.04.2015


Отговори (4)


Ако можете да използвате компилатор, съвместим с c++11, това би бил перфектен случай за използване на списък с инициализатор, използващ агрегирана инициализация.

mybuf() : buf{0, 0}
{}
person Simon Gibbons    schedule 20.04.2015
comment
Благодаря, това работи! Какъв би бил правилният начин, ако не можете да използвате C++11? - person godfatherofpolka; 20.04.2015

Един "правилен" начин, ако компилаторът ви поддържа C++11, е да използвате напр.

mybuf() : buf{0, 0} {}
person Some programmer dude    schedule 20.04.2015
comment
Благодаря, това работи! Какъв би бил правилният начин, ако не можете да използвате C++11? - person godfatherofpolka; 20.04.2015

Това няма нищо общо със смесването на C и C++. Опитвате се да инициализирате членове, които не съществуват; че съществуват в базов клас не е достатъчно. Трябва да инициализирате самата база.

В този случай използвайте агрегатна инициализация:

class mybuf : public buf
{
public:
    mybuf() : buf{0, 0} {}
};
person Lightness Races in Orbit    schedule 20.04.2015
comment
Благодаря, това работи! Какъв би бил правилният начин, ако не можете да използвате C++11? - person godfatherofpolka; 20.04.2015
comment
разширение на GCC, може би; buf({0,0}) - person Lightness Races in Orbit; 20.04.2015

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) {};

ще работи.

Виждал съм, че това работи с някои компилатори, но нямам удобен стандарт, за да проверя дали е стандартен или разширение.

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};
};
person Peter    schedule 20.04.2015
comment
Що се отнася до вашия втори метод: GCC 4.9 го приема, CLang 3.6rc2 дава -Wuninitialized предупреждение на реда на конструктора, ICC 13 отхвърля то с грешка 409 в реда на конструктора и MSVC 17 (VS2012) отхвърля инициализатора с C2059 'неочаквана {' грешка, последвана от C2334 'неочакван токен(и) предшестващ '{'' и ​​след това C2065 ' недеклариран идентификатор" в дефиницията на конструктора. Бих казал, че е или GCCism/GCC разширение, или UB. - person LThode; 20.04.2015