Динамическое приведение массива ** в c ++ - PullRequest
0 голосов
/ 02 июня 2018

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

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

void function (const A &a) {
    if(B *b = dynamic_cast<B*>(a)){
        cout << "B" << endl;
    }
    if(C *c = dynamic_cast<C*>(a)){
        cout << "C" << endl;
    }
}

int main () {
    A **array = new A* [2];
    array [0] = new B;
    array [1] = new C;

    function (array [0]); // To print B
    function (array [1]); // To print C
}

Но выдает ошибку, которая говорит:

cannot dynamic_cast ‘a’ (of type ‘const class A’) to type ‘class B*’ (source is not a pointer)

Что я могу сделать?

Ответы [ 3 ]

0 голосов
/ 02 июня 2018

Я исправил ваш код, чтобы он работал так, как вы хотите.Но я предлагаю вам не делать этого: использование new / delete, new[] / delete[] и необработанных указателей не являются наилучшей практикой.Использование dynamic_cast очень неприятный запах кода.

#include <iostream>

using std::cout;
using std::endl;

namespace
{

class A
{
public:
  virtual ~A() = default;
};

class B: public A
{
};

class C: public A
{
};

void function (A const& a)
{
  if (B const* b = dynamic_cast<B const*>(&a))
  {
    cout << "B" << endl;
  }

  if (C const* c = dynamic_cast<C const*>(&a))
  {
    cout << "C" << endl;
  }
}

} // anonymous namespace

int main ()
{
  A* array[2] =
  {
    new B,
    new C
  };

  function(*array[0]); // To print B
  function(*array[1]); // To print C
}
0 голосов
/ 02 июня 2018

Как уже говорили другие, почему бы не пропустить приведение? Более того, если вы хотите, чтобы ваши производные классы демонстрировали другое поведение, почему бы не определить явно это другое поведение?То есть использование dynamic_cast<> говорит о вашем намерении, как и альтернатива.

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

class A {
public:
    virtual void operator()() {
        std::cout << "A\n";
    }

    virtual void print() {
        std::cout << "A\n";
    }

    virtual ~A() = default;
};

class B : public A {
public:
    void operator()() override {
        std::cout << "B\n";
    }

    void print() override  {
        std::cout << "B\n";
    }
};

class C : public A {
public:
    void operator()() override {
        std::cout << "C\n";
    }

    void print() override {
        std::cout << "C\n";
    }
};

int main()
{
    std::vector<A*> v;
    auto pa = new A{};
    auto pb = new B{};
    auto pc = new C{};

    v.push_back(pa);
    v.push_back(pb);
    v.push_back(pc);

    for(auto& elem : v)
        elem->print();

    delete pa;
    delete pb;
    delete pc;

    return 0;
}

Я думаю, что это часть ответа на ваш вопрос.Я думаю, что на другую часть вашего вопроса можно ответить:

std::vector<A> vv;
A a;
B b;
C c;

a(); // A
b(); // B
c(); // C

vv.push_back(a);
vv.push_back(b);
vv.push_back(c);

for(auto& elem : vv)
    elem(); // ?
0 голосов
/ 02 июня 2018

Применение динамического приведения к адресу a, например dynamic_cast<const B*>(&a).Хотя это правда, что ссылка - это указатель изнутри (своего рода), вы не можете просто рассматривать его как указатель.

Однако я бы не советовал писать что-то подобное, что не масштабируется.

PS - Как подсказывают комментаторы, вам нужно динамически приводить к константному указателю, а ваш пример - к неконстантному.

...