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

В Смешивание кода 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 ++: Инициализация унаследованных field и Инициализировать защищенные элементы родительского элемента с помощью списка инициализации (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
почему вы помещаете внешний C вокруг своей структуры? нет необходимости.   -  person AndersK    schedule 20.04.2015
comment
@CyberSpock См. Исходный источник кода, речь идет о смешивании кода C и C ++, а файл заголовка содержит объявления некоторых функций. Я отредактировал приведенный выше код, чтобы прояснить это.   -  person godfatherofpolka    schedule 20.04.2015
comment
@godfatherofpolka структура - это структура, будь то C или C ++. нет причин заключать его в блок extern 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