Я не ожидаю C ++, как вы, несомненно, заметите. Но я пытаюсь «обновить» какой-то старый код C до C ++. В процессе я пытаюсь продвигать старые структуры в классах. Я нашел эту статью Oracle о некоторых вещах, которые я пытаюсь сделать.
http://www.oracle.com/technetwork/articles/servers-storage-dev/mixingcandcpluspluscode-305840.html
Но 2 вещи. В статье не рассматривается более сложный случай, который у меня есть. И мой «обходной путь», похоже, не дает последовательных результатов. Итак, я приведу некоторые детали.
Старая структура в стиле C:
typedef struct
{
int ia;
float fa;
...
} Struct_A;
typedef struct
{
Struct_A sA;
int ib;
float fb;
...
} Struct_B;
C ++
В соответствии со статьей Oracle, я должен иметь возможность рекламировать Struct_A в классе и по-прежнему иметь возможность использовать версию класса со старыми функциями C. Вот, видимо, как:
class CStruct_A : public Struct_A // Inherits from C- Struct_A
{
public:
CStruct_A() : ia(0), fa(0.0f) {}
}
Пауза. Прямо здесь, у меня уже есть проблема. Я не могу инициализировать элементы C-Structure, как указано в статье и как показано выше. Компилятор не принимает это. Я должен переписать класс как:
class CStruct_A : public Struct_A
{
public:
CStruct_A()
{
ia = 0;
fa = 0.0f;
}
}
Итак, это первый знак вопроса. Не большая сделка, но статья утверждает, что это может быть сделано.
Далее, более сложная проблема. Продвижение Struct_B, который содержит член Struct_A. Я хочу убедиться, что конструктор класса A используется для инициализации переменных. Но я не уверен, как это заставить. В моем коде C ++, если у меня есть что-то вроде:
{
CStruct_B *pCStrb = new CStruct_B();
...
}
Конструктор класса B вызывается, но не класс A. Обходной путь у меня хромает … Но это единственное, что я могу пока выяснить. Я объявляю внутреннюю приватную функцию ini () в классе A, делаю класс B другом и вызываю init () из конструктора класса B.
class CStruct_A : public Struct_A
{
friend class CStruct_B;
public:
CStruct_A() { init(); }
private:
void init()
{
ia = 0;
fa = 0.0f;
}
}
class CStruct_B : public Struct_B
{
public:
CStruct_B()
{
ib = 0;
fb = 0.0f;
static_cast<CStruct_A *>(&sA)->init();
}
}
У меня есть еще вопросы, но это, вероятно, уже слишком долго.
Любая помощь будет оценена.
Я пролистал «статью Oracle», на которую вы ссылались, и в этой статье я не нахожу ничего, что предлагало бы инициализировать базовые классы так, как вы утверждаете в статье, или приводило пример с чем-нибудь близким к вашему синтаксису. пытаюсь скомпилировать.
Конструкторы классов C ++ могут только инициализировать членов своего класса. Они не могут инициализировать ни одного члена своего суперкласса непосредственно из своего конструктора.
Сказав это, некоторые компиляторы могут предлагать свои собственные специфичные для компилятора языковые расширения. Например, gcc 5.1 примет следующий код в режиме -std = c ++ 11:
typedef struct
{
int ia;
float fa;
} Struct_A;
class CStruct_A : public Struct_A {
public:
CStruct_A() : Struct_A({
.ia=1,
.fa=0,
})
{
}
};
Но это ужасно неэффективно и не является стандартным C ++ (так как gcc предупредит вас в -Wpedantic
Режим).
Хорошо …
Чтобы закрыть этот вопрос, я предполагаю, что единственный способ инициализации подструктуры, который я нашел, это в значительной степени делать то, что я делал в моем обходном пути. Я не нашел другого прямого пути. Я думаю, это не имеет большого значения. Я был просто введен в заблуждение оригинальной статьей.
Теперь старый код имеет глобальный Struct_B, определенный как «extern», и моя новая программа на С ++ должна его выделить. Чтобы иметь возможность использовать его продвинутые функции, оставаясь «определенными» со старой точки зрения кода C, я объявил его следующим образом:
{
Struct_B *pCStrb = new CStruct_B();
...
}
Поэтому я объявляю это как старую c-структуру, но выделяю ее версией класса. Это отличается от того, что я первоначально написал выше, где я использовал версию «C ++», чтобы объявить это. Это было явно неправильно, поскольку старый C-код ничего не знает о структуре CStruct_B.
Во всяком случае … кажется, делает то, что я хотел, хотя и не совсем так, как я хотел.
Спасибо за помощь.
Для решения вашей первой проблемы. С точки зрения C ++ эти структуры C считаются агрегатами. Так что вы можете сделать:
class CStruct_A : public Struct_A
{
public:
CStruct_A() : Struct_A{0, 0.0f} {};
}
Это прекрасно работает для меня. Инициализатор фигурных скобок просто инициализирует Struct_A в порядке своих членов.
Лучшее, что я вижу для решения вашей второй проблемы, — это дать CStruct_A неявное преобразование обратно в Struct_A и использовать его.
struct A {
double x;
int y;
};
class Ac : public A {
public:
Ac() : A{0.0, 1} {};
operator A() const { return A{x, y}; }
};
struct B {
B() : a(Ac()) {};
A a;
};
Изменить: все, что сказал, я не совсем уверен, что наследование это первое место, где я бы хотел решить эту проблему. Я почти наверняка предпочел бы начать с инкапсуляции структур стиля C в классах C ++ и перейти оттуда.
Чтобы уточнить, как бы я это сделал:
class CStruct_A {
// ... various other code, initializes a carefully etc
public:
Struct_A * getA() { return &a; }
private:
Struct_A a;
}
Теперь, учитывая некоторые функции:
void func(Struct_A * var);
Назовите это так:
CStruct_A my_var();
func(my_var.getA());
Это может быть не так сложно, как использование наследования, но все просто, работает, позволяет полностью инкапсулировать структуры C и решать, как они инициализируются, компилятор защитит вас от случайного вызова func (myvar) и т. Д. Я бы предпочел это, а не наследование, если нет более веской причины использовать наследование, чем вы описали.