2015-05-16 2 views
-4

У меня проблема с передачей массива указателей на функцию.C++ передающий массив указателей на функцию

Класс CTree01 является дочерью CDecorationObj. Когда я использую цикл, он работает нормально.

Вот мой код:

CTree01 *trees01; 
int numTree01 = ...; 

trees01 = new CTree01[numTree01]; 

//main loop 
for(int i=0;i<numTree01;i++) 
    { 
     { 
      //Everything is working okay here, renders all trees 
      glPushMatrix(); 
      trees01[i].DrawOnTerrain(camera); 
      glPopMatrix(); 
     } 
    } 

, но так как я заменил на с функцией, она больше не работает:

void DrawDecorationType(CDecorationObj* objs, int number, CCamera *camera) 
{ 
    int x,z; 
    for(int i=0;i<number;i++) 
    { 
     { 
      glPushMatrix(); 
      objs[i].DrawOnTerrain(camera); 
      glPopMatrix(); 
     } 
    } 
} 

//main loop 
DrawDecoration(trees01, numTree01, camera); 

Когда я в этой функции:

он работает, и он падает только тогда, когда я обрабатываю объекты с индексом> 0, поэтому я думаю, что это должна быть проблема с параметром, переданным в функция.

+0

Вы лечите свои OBJS [] - массив с типом 'CDecorationObj', который, безусловно, имеет различную длину, чем' CTree01 'Давайте предположим, что' CDecorationObj' имеет размер 10 байт, а 'CTree01' равно 20, когда вы обращаетесь к' objs [1] ', вы находитесь на полпути в следующий объект дерева (по памяти), и вы ошибаетесь адрес для 'this' при вызове' DrawOnTerrain'. Попробуйте использовать указатели на свои внутренние элементы (например, 'CTree **' и 'CDecorationObj **') – PuerNoctis

+0

вы не должны быть 'new'ing и' delete'ing просто потому, что вам особенно не нужны исходные указатели как массивы. Google 'std :: vector'. –

+0

Я заменил «CDecorationObj * objs» на «CDecorationObj ** objs», но теперь я получил ошибку «не может преобразовать параметр 1 из« D_CTree02 ** »в« CDecorationObj ** » – Barcio77

ответ

2

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

Допустим, у вас есть:

struct Foo 
{ 
    char a; 
}; 

struct Bar : Foo 
{ 
    char b; 
}; 

sizeof(Foo) является 1 и sizeof(Bar) является 2.

И вы создаете массив Bar объекта с помощью:

Bar* barPtr = new Bar[2]; 

Компоновка памяти, barPtr указывает на внешний вид, как:

Bar(0) Bar(1) 
|  | 
v  v 
+---+---+---+---+ 
| a | b | a | b | 
+---+---+---+---+ 

Если передать этот указатель на функцию а Foo*, эта функция будет интерпретировать память как (начиная с sizeof(Foo) == 1):

Foo(0) 
| Foo(1) 
| | 
v v 
+---+---+ 
| a | a | 
+---+---+ 

Как вы можете видеть, Foo(1) на самом деле не является объектом Foo. Это действительно Bar под-объект Bar(0). Это может легко привести к неопределенному поведению. В зависимости от типов данных базовый класс и производный класс могут легко сбой вашей программы.

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

2

Очень хорошее объяснение от R Sahu. Он четко описывает, почему ваш код не работает и заслуживает того, чтобы его приняли.

Итак, что вы можете сделать вместо этого?

Насколько я понимаю, вы хотите передать весь свой CTree01 функции в один звонок и выполнить эту функцию для всех ваших CTree01.

Единственный способ, которым я знаю, - сделать контейнер (т. Е. Массив, вектор), содержащий указатели базового класса вместо CTree01.

Что-то вроде этого:

class A 
{ 
public: 
    A() { cout << "A constructor" << endl;} 
    virtual ~A() { cout << "A destructor" << endl;} 
    void hello() { cout << "Hello from A" << endl;} 
}; 

class B : public A 
{ 
public: 
    B() { cout << "B constructor" << endl;} 
    ~B() override { cout << "B destructor" << endl;} 
}; 

void f(array<A*,2>& t) 
{ 
    for(auto e : t) 
    { 
     e->hello(); 
    } 
} 

int main() 
{ 
    array<A*,2> z; // Base class pointer array 
    z[0]=new B;  // but it can still hold pointers to B 
    z[1]=new B; 
    f(z); 
    delete z[0]; 
    delete z[1]; 
    return 0; 
} 

или с использованием вектора вместо массива

class A 
{ 
public: 
    A() { cout << "A constructor" << endl;} 
    virtual ~A() { cout << "A destructor" << endl;} 
    void hello() { cout << "Hello from A" << endl;} 
}; 

class B : public A 
{ 
public: 
    B() { cout << "B constructor" << endl;} 
    ~B() override { cout << "B destructor" << endl;} 
}; 

void f(vector<A*>& t) 
{ 
    for(auto e : t) 
    { 
     e->hello(); 
    } 
} 

int main() 
{ 
    vector<A*> z; 
    z.push_back(new B); 
    z.push_back(new B); 
    f(z); 
    delete z[0]; 
    delete z[1]; 
    return 0; 
} 
+0

Хорошо, я понимаю это сейчас, он работает! Спасибо за то, что вы записали это решение – Barcio77

Смежные вопросы