LINUX.ORG.RU

Сломал мозг

 


0

4

Возвращаясь к предыдущей теме: http://www.linux.org.ru/forum/development/9153691

Этот подход получился неудачным.
Поэтому попробую заново сформулировать вопрос по-другому.

Есть 10-20 материалов, у которых есть свойства p1, p2, ...
(в зависимости от материала набор этих свойств может отличаться).
Это можно задать через struct mat{...}. Также у каждого материала есть вычисляемые функции, т.е. методы (у каждого они разные).
Можно все это обернуть в class на основе виртуального класса.

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

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

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

З.ы. Если это возможно, то в рамках стандартного с++98.

★★★★★

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

А где тут проблема? Разве этого сделать нельзя?

UVV ★★★★★
()
Ответ на: комментарий от UVV

вот пример:

class A{
  public:
    double p1, p2;
    virtual double fun(p1,p2) = 0;
}

class B{
  public:
    double p1,p2;
    double fun(p1,p2) {...};
}

class C{
  public:
    double p1,p2;
    double fun(p1,p2) {...};
}

void proc(A* a) {
  ...
}

int main() {
  B b;
  C c;
  A* a[2];
  a[0]=&b;
  a[1]=&c;

  proc(a);
}
Zodd ★★★★★
() автор топика
Ответ на: комментарий от Zodd

хосспаде. а наследоваться от A? это ж тебе не петон.

class A {
  public:
    double p1, p2;
    virtual double fun(p1,p2) = 0;
};

class B: public A {
  public:
    double fun(p1,p2) {...};
};

class C: public A {
  public:
    double fun(p1,p2) {...};
};
x0r ★★★★★
()
Последнее исправление: x0r (всего исправлений: 1)
Ответ на: комментарий от UVV

Наследуйтесь от какого-нибудь абстрактного для ваших сущностей класса, передавайте в виде указателей на абстрактный класс, там если надо dynamic_cast.

Y ★★
()

Также у каждого материала есть вычисляемые функции, т.е. методы (у каждого они разные).

Если набор методов одинаковый, а отличается только реализация, то наследование - это то, что тебе нужно.

Norgat ★★★★★
()
Ответ на: комментарий от Zodd

фу-фу есть же vector. 2013-й год на дворе, с++11.

class A { ... };
class B : public A { ... };
class C : public A { ... };

void proc(vector<shared_ptr<A>> & a) {
 ...
}

int main() {
  vector<shared_ptr<A>> a;
  a.push_back(shared_ptr<A>(new B()));
  a.push_back(shared_ptr<A>(new C()));

  proc(a);
  return 0;
}
invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)
Ответ на: комментарий от invy

template <typename T>
void p(T &arg)
{
  for_each(arg.begin(), arg.end(), [] (shared_ptr <A> &a) {
    a->foo();
  });
}

int main()
{
  list <shared_ptr <A> > a;
  a.push_back(make_shared <B> ());
  a.push_back(make_shared <C> ());
  p(a);
}
nanoolinux ★★★★
()
Ответ на: комментарий от x0r

Вот http://ideone.com/xaEulK

prog.cpp:6:24: error: ‘p1’ is not a type
prog.cpp:6:27: error: ‘p2’ is not a type
prog.cpp:11:16: error: ‘p1’ is not a type
prog.cpp:11:19: error: ‘p2’ is not a type
prog.cpp: In member function ‘virtual double B::fun(int, int)’:
prog.cpp:12:6: error: ‘cout’ was not declared in this scope
prog.cpp:13:2: warning: no return statement in function returning non-void [-Wreturn-type]
prog.cpp: At global scope:
prog.cpp:18:16: error: ‘p1’ is not a type
prog.cpp:18:19: error: ‘p2’ is not a type
prog.cpp: In member function ‘virtual double C::fun(int, int)’:
prog.cpp:19:3: error: ‘cout’ was not declared in this scope
prog.cpp:20:2: warning: no return statement in function returning non-void [-Wreturn-type]
prog.cpp: In function ‘void proc(A**)’:
prog.cpp:24:12: error: no matching function for call to ‘A::fun()’
prog.cpp:24:12: note: candidate is:
prog.cpp:6:20: note: virtual double A::fun(int, int)
prog.cpp:6:20: note:   candidate expects 2 arguments, 0 provided
Zodd ★★★★★
() автор топика

Кстати, внутри функции, в которую передаете список, вы сможете пользоваться только методами, описанными в интерфейсе базового класса. Это если писать чисто, красиво и без костылей.

Если внутри функции нужно использовать методы, уникальные для каждого из классов - тут надо думать.

grondek
()
Ответ на: комментарий от grondek

Если внутри функции нужно использовать методы, уникальные для каждого из классов - тут надо думать.

dynamic_cast<> например. но будет не очень красиво.

invy ★★★★★
()
Ответ на: комментарий от invy

шибко костыльный каст, кроме того функции надо будет иметь информацио обо всех классах иерархии, что сразу лишает смысла организацию иерархию.

grondek
()
Ответ на: комментарий от Zodd

Сделайте меня развидеть это!

Проблема не в наследовании, проблема в том что Вы не знаете С++. Каждую ошибку конечно разобрать можно, но это не поможет - проект Вы все равно с таким уровнем не сделаете. Возьмите нормальную книжку по плюсам и читайте-читайте-читайте...

AIv ★★★★★
()

Вот ошибки исправил, вроде собирается. Только как-то костыльно выглядит.

#include <iostream>
using namespace std;
 
class A {
public:
    double p1, p2;
    virtual double fun(double p1,double p2) = 0;
    virtual ~A() {}
};
 
class B: public A {
public:
    double fun(double p1,double p2) {
        cout << p1+p2 << endl;
    };
};
 
class C: public A {
public:
    double fun(double p1,double p2) {
        cout << p1-p2 << endl;;
    };
};
 
void proc(A** a,double p1,double p2) {
    for (int i = 0; i < 2; ++i)
        a[i]->fun(p1,p2);
}
 
int main() {
    double p1, p2;
    p1 = 1.0;
    p2 = 2.0;
    B b;
    C c;
    A* a[2];
    a[0]=&b;
    a[1]=&c;
 
    proc(a,p1,p2);
}
Zodd ★★★★★
() автор топика
Ответ на: комментарий от AIv

Да ладно, не придирайся.Я вообще то не программист по образованию. Писал я это по памяти, а т.к. на работе нет компилятора сделал несколько ошибок.

Лучше скажи как код сделать более красивым.

Zodd ★★★★★
() автор топика
Ответ на: комментарий от Zodd

как-то костыльно выглядит

welcome to c++. enjoy.

x0r ★★★★★
()
Ответ на: комментарий от Zodd

Я тоже ни разу не программист.

Лучше скажи как код сделать более красивым.

Выучите нормально С++ - и оно само получится;-)

Без знания специфики задачи ничего красивее сделать не получится, там все ОК кроме кучи ошибок.

AIv ★★★★★
()
Ответ на: комментарий от AIv

Я больше над концепцией думал и ошибки пропустил. Знание плюсов постепенно повышаю. Но на это так не хватает пока времени(

Zodd ★★★★★
() автор топика
Ответ на: комментарий от Zodd
#include <iostream>
#include <vector>
using namespace std;

struct A // struct - экономия места
{
    virtual ~A() {}
    virtual void fn(double a, double b) = 0;
};

struct B : A
{
    virtual ~B() {} // в потомках тоже надо указывать
    virtual void fn(double a, double b) // разрешить переопределение в потомках
    { cout << a + b << endl; }
};

struct C : A
{
    virtual ~C() {}
    void fn(double a, double b)
    { cout << a - b << endl; }
};

template<class Iter, class T>
void proc(Iter beg, Iter end, T a, T b)
{ for(;beg != end; ++beg) (*beg)->fn(a, b); }

int main()
{
    B b1, b2;
    C c1, c2;
    A *arr[] = { &b1, &c2, &b2, &c1 }
    , **arr_end = arr + sizeof(arr) / sizeof(arr[0]);
    proc(arr, arr_end, 321, 123);
    
    vector<A *> vec(arr, arr_end);
    proc(vec.begin(), vec.end(), 123, 321);

    return 0; // программа должна вернуть значение
}
numas@gnunix:~$ g++ -O2 -std=c++98 -Wall -o app app.cpp
numas@gnunix:~$ ./app 
444
198
444
198
444
-198
444
-198
numas@gnunix:~$ 
numas13
()
Ответ на: комментарий от nanoolinux

p1 и p2 - это должно быть внутри класса. Вот после исправлений:

#include <iostream>
using namespace std;
 
class A {
public:
    double p1, p2;
    virtual void fun() = 0;
    virtual ~A() {}
};
 
class B: public A {
public:
    void fun() {cout << p1+p2 << endl;}
    virtual ~B() {}
};
 
class C: public A {
public:
    void fun() {cout << p1-p2 << endl;}
    virtual ~C() {}
};
 
void proc(A** a) {
    for (int i = 0; i < 2; ++i)
        a[i]->fun();
}
 
int main() {
    B b;
    C c;
    b.p1 = 2.0;
    b.p2 = 1.5;
    c.p1 = 3.0;
    c.p2 = -0.5;
    A* a[2];
    a[0]=&b;
    a[1]=&c;
 
    proc(a);

return 0;
}

Что-то я устал сегодня и много ошибок делаю(

Zodd ★★★★★
() автор топика
Последнее исправление: Zodd (всего исправлений: 2)
Ответ на: комментарий от numas13

Прокомментируй пожалуйста эти строки. Не совсем понял, что здесь делается.

, **arr_end = arr + sizeof(arr) / sizeof(arr[0]);
proc(arr, arr_end, 321, 123);
    
vector<A *> vec(arr, arr_end);
Zodd ★★★★★
() автор топика
Ответ на: комментарий от Zodd

гуглите STL и std::vector. Вообще говоря далеко не всегда эта шняга нужна.

AIv ★★★★★
()

хочу передать массив структур в процедуру

Быстро решительно расхотеть. Полиморфные классы в массивах не работают. Используйте вектор.

no-such-file ★★★★★
()
Ответ на: комментарий от AIv

Не надо, давно на С++ не программировал. Начинаю подзабывать, тревожный звоночек. :)

numas13
()
Ответ на: комментарий от no-such-file

Полиморфные классы в массивах не работают. Используйте вектор.

А можно раскрыть этот тезис? В частности, очень интересно чем вектор так кардинально отличается от массива, что полиморфные классы в нем уже работают? И почему полиморфные классы не работают в массивах?

AIv ★★★★★
()
Ответ на: комментарий от Zodd
, **arr_end = arr + sizeof(arr) / sizeof(arr[0])

Определяем конец нашего массива.

proc(arr, arr_end, 321, 123);

Т. к. сигнатуру функции proc я изменил, теперь она работает с любыми контейнерами, которые предоставляют прямые итераторы.

vector<A *> vec(arr, arr_end);

Выше ответили.

numas13
()
Ответ на: комментарий от numas13

Почему предлагаешь делать через структуру, а не через классы. Какие есть преимущества кроме экономии места?

Zodd ★★★★★
() автор топика
Ответ на: комментарий от Zodd

Если у тебя 10 определений классов, дополнительно 10 строк. :)

Мы же не индусы, нам за кол-во символов не платят.

numas13
()
Ответ на: комментарий от numas13

Ясно - просто так короче или красивее. Т.е. в общем без разницы, что хочешь, то и используешь.

Zodd ★★★★★
() автор топика
Ответ на: комментарий от AIv

И почему полиморфные классы не работают в массивах?

Потому что в массивах используется простая адресная арифметика, которой ничего не известно про размер объекта. Впрочем, ТС уже получил совет использовать массив указателей на объект, а не просто массив объектов.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Потому что в массивах используется простая адресная арифметика, которой ничего не известно про размер объекта.

O_O?????

А в векторе таких проблем значит нету? И как же их там порешали?

AIv ★★★★★
()
Ответ на: комментарий от numas13

После доработки код получился вот таким:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
 
struct A {
    double p1, p2;
    virtual void fun() = 0;
    virtual ~A() {}
};
 
struct B: A {
    void fun() {cout << p1+p2 << endl;}
};
 
struct C: A {
    void fun() {cout << p1-p2 << endl;}
};
 
void proc(vector<A*>& a) {
    for_each(a.begin(),a.end(),mem_fun(&A::fun));
}
 
int main() {
    B b;
    C c;
    b.p1 = 2.0;
    b.p2 = 1.5;
    c.p1 = 2.0;
    c.p2 = 1.5;

    vector<A*> a(2);
    a.at(0) = &b;
    a.at(1) = &c;
 
    proc(a);

    return 0;
}
Zodd ★★★★★
() автор топика
Ответ на: комментарий от indie

Я еще не до конца разобрался со спецификой моей задачи. Понадобится ли дальше возможности класса или нет?..

Zodd ★★★★★
() автор топика

Царь в треде.

typedef struct {
  uint8_t id;
  uint64_t a, b, c;
} m_id0_t;

typedef struct {
  uint8_t id;
  uint64_t a, b;
} m_id1_t;

typedef void *(*id_headler_t)(void *);

void * id0_headler(void * ptr) {
  m_id0_t * my_data = ptr;
  fprintf(stderr, "id = %u, a = %lu, b = %lu, c = %lu\n", my_data->id, my_data->a, my_data->b, my_data->c);    
  return ++my_data;
}

void * id1_headler(void * ptr) {
  m_id1_t * my_data = ptr;
  fprintf(stderr, "id = %u, a = %lu, b = %lu\n", my_data->id, my_data->a, my_data->b);    
  return ++my_data;
}

id_headler_t id_headles[] = {
  id0_headler,
  id1_headler
};

#define END 0xff
inline void call_headers(void * ptr) {
  do {
    ptr = id_headles[*(uint8_t*)ptr](ptr);
  } while(*(uint8_t*)ptr != END);
}

inline m_id0_t * create_id0(m_id0_t * ptr, uint64_t a, uint64_t b, uint64_t c) {
  ptr->id = 0,ptr->a = a, ptr->b = b, ptr->c = c;
  return ++ptr;
}
inline m_id1_t * create_id1(m_id1_t * ptr, uint64_t a, uint64_t b) {
  ptr->id = 1, ptr->a = a, ptr->b = b;
  return ++ptr;
}
inline void * set_end(uint8_t * ptr) {
  *ptr = END;
  return ++ptr;
}

int main(void) {
  void * pull = malloc(100500), * begin = pull;
  pull = create_id0(pull, 100123, 100223, 100323);
  pull = create_id1(pull, 200123, 200223);
  pull = set_end(pull); 
  call_headers(begin);
}
superhackkiller1997
()
Ответ на: комментарий от AIv

Я написал тебе ещё одну портянку, которую ты захочешь развидеть.

Как такое запилить на классах?

superhackkiller1997
()
Ответ на: Царь в треде. от superhackkiller1997

Ах да, тут ещё без глобальных переменных, а с ними будет ещё красивее и прям реально царски. Никаким плюсам так не снилось.

superhackkiller1997
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.