2012-06-04 2 views
3

Я работаю в простом C (встроенный проекта, мало памяти) и у меня есть структураКак наследовать структуру в простом C

typedef struct 
{ 
    int x; 
    int y; 
    int z; 
    float angle; 
    float angle1; 
    float angle2; 
} Kind1; 

Есть случаи, когда мне нужно все поля, и есть случаи, когда мне нужны x, y и только угол.

В C++ я бы создал базовый класс с этими тремя полями, наследовал бы от него еще один класс с дополнительными 3 полями и создавал бы экземпляр того или другого в случае необходимости. Как я могу подражать этому поведению в простой C?

Я знаю, что я могу сделать что-то вроде

typedef struct 
{ 
    int x; 
    int y; 
    float angle; 
} Kind1; 

typedef struct 
{ 
    Kind1 basedata; 
    int z; 
    float angle2; 
    float angle3; 
} Kind2; 

, но тогда я не могу передать указатель на Kind2, где запрашивается указатель на Kind1.

Я знаю, что можно приписать и смещать указатель, мне просто интересно, есть ли лучший, более безопасный способ.

+0

использование объединение Kind1 и Kind2 – RolandXu

+1

Возможно дубликата http://stackoverflow.com/q/10872130/905902, в том числе синтаксических ошибок. – wildplasser

+0

@wildplasser: Странно, что я пропустил это, я попытался сначала найти SO. BTW, синтаксические ошибки - что вы имеете в виду? Очевидно, это своего рода псевдокод. – Flot2011

ответ

5

Я знаю, что можно типаж и смещение указателя

Не обязательно:

void foo(Kind1*); 
struct Kind2 
{ 
    Kind1 basedata; 
    int z; 
    float angle2; 
    float angle3; 
} 

//... 
Kind2 k; 
foo(&(k.basedata)); 
2

Вы можете сделать это так же, как вы бы в C++:

struct Kind1 
{ 
    int x; 
    int y; 
    float angle; 
} 

struct Kind2 
{ 
    int z; 
    float angle2; 
    float angle3; 
} 

struct Kind 
{ 
    Kind1 k1; 
    Kind2 k2; 
} 
+0

Проект предназначен для встроенных устройств, все дело в том, чтобы сэкономить память, иначе я может просто жить с Kind2 всегда. – Flot2011

+0

Убрал мой комментарий, получил его слишком поздно. Благодарю. – BigMike

+0

@ Flot2011: звучит как преждевременная оптимизация, но вы можете просто использовать Kind1, Kind2 или Kind, подходящие для любого конкретного варианта использования. –

2

Это невозможно в простой C, язык не имеет таких функций. Тем не менее, вы можете упростить типы и смещения с помощью макросов с предварительным процессором.

0

В случае ограниченного объема памяти, сохранить здравомыслие, объявив два различных структур:

struct Kind1 
{ 
    int x; 
    int y; 
    float angle; 
} 

struct Kind2 
{ 
    int x; 
    int y; 
    int z; 
    float angle; 
    float angle2; 
    float angle3; 
} 

Однажды мне пришлось работать код, который использовал соединение и препроцессора #define с, чтобы сделать код выглядеть более читаемым. Однако это быстро приводит к безумию. Если две структуры фактически обрабатываются как подкласс, то переставлять поля является наименьшим злом:

struct Kind1 
{ 
    int x; 
    int y; 
    float angle; 
} 

struct Kind2 
{ 
    int x; 
    int y; 
    float angle; 
    // extended data: 
    int z; 
    float angle2; 
    float angle3; 
} 

до тех пор, как они тщательно используются при литье. Если что-то пойдет не так, хотя, действительно, нужно отлаживать версию namechecking, чтобы доказать, что все сделано правильно.

struct Kind1 
{ 
    char variant[6]; // initialized to "kind1" 
    int x; 
    int y; 
    float angle; 
} 

struct Kind2 
{ 
    char variant[6]; // initialized to "kind2" 
    int x; 
    int y; 
    float angle; 
    // extended data: 
    int z; 
    float angle2; 
    float angle3; 
} 

function_expecting_kind2 (struct kind2 *p) 
{ 
    if (strcmp (p->variant, "kind2")) 
      error ("function expecting kind2 got '%s' instead", p->variant); 
    ... 
} 
0

Один из способов, о котором я могу думать, который сохранит не более 2 * sizeof (float) байт.

struct Kind2 
{ 
    int z; 
    float angle2; 
    float angle3; 
} 

struct Kind1 
{ 
    int x; 
    int y; 
    float angle; 
    struct Kind2 *k2; 
} 

здесь вся экономия будет основана на том, сколько памяти указатель ест.

Инициируйте указатель, только если это необходимо.

2

Примеры ниже предполагают эти определения.

struct base { char c; } *a_base; 
struct sub { struct base b; int i; } *a_sub; 

Ваш "пример" это на самом деле (простейший) правильное решение.

, но тогда я не могу передать указатель на Kind2, где запрашивается указатель на Kind1.

Да, вы можете. Ниже из стандарта C11, но предыдущие версии имели те же гарантии [править].

n1570 6.7.1.1.15

... Указатель на объект структуры, соответствующим образом преобразованы, указывает на его начальном элементе (или, если этот член битовое поле, а затем в блок в который он проживает), и наоборот. В структурном объекте может быть неназванное дополнение, но не в начале.

Поэтому (struct base*)a_sub == &a_sub->b и ((struct base*)a_sub)->c == a_sub->b.c

Так до тех пор, как ваш «супер-структура» является первым членом вашей «суб-структуры» можно рассматривать, как один другой при доступе по ссылке. В принципе, не делайте этого.

void copy(struct base *from, struct base *to) 
{ 
    *to = *from; // Oops, you just lost half your object. 
} 
Смежные вопросы