rtti — C ++ Динамическое связывание в аргументе метода

Недавно я хотел, чтобы c ++ динамически разрешал член / функцию по входному параметру, который есть в некоторых производных версиях. Вот что я имею в виду:

#include <iostream>

class Base {
};

class DerivedA : public Base {
};

class DerivedB : public Base {
};

class DerivedC : public Base {
};

class Test {
public:
void world( DerivedA *instance )
{
std::cout << "DerivedA" << std::endl;
}

void world( DerivedB *instance )
{
std::cout << "DerivedB" << std::endl;
}

void world( Base *instance )
{
std::cout << "Base" << std::endl;
}
};

int main()
{
Base *a = new Base;
Base *b = new DerivedA;
Base *c = new DerivedB;
Base *d = new DerivedC;

Test hello;
hello.world( a );
hello.world( b );
hello.world( c );
hello.world( d );

return 0;
}

Поведение я В РОЗЫСКЕ это:

Base
DerivedA
DerivedB
Base

Но наверняка на выходе я ДЕЙСТВИТЕЛЬНО получить это:

Base
Base
Base
Base

Я понимаю, что динамическое связывание — это другой способ, разрешающий правильную функцию-член в производных классах base, и не таким образом — но может ли это работать каким-либо образом для этого?

Может быть, я упускаю только важный момент ..

Однако заранее большое спасибо!

Себастьян

0

Решение

Тип a, b, c а также d являются все Base*, Компилятор не отслеживает «что содержит переменная». Если это то, что вы хотите сделать, вам нужно использовать виртуальную функцию в классе, из которого вы производите, например:

class Base {
public:
virtual const char* MyName() { return "Base"; }
};

class DerivedA : public Base {
public:
virtual const char* MyName() { return "DerivedA"; }
};
... similiar for all derived classes ...

void world( Base *instance )
{
std::cout << instance->MyName() << std::endl;
}

(Изменить: чтобы получить именно то поведение, которое вы перечислите в первом случае, вам НЕ нужно реализовывать функцию MyName () в классе DerivedC)

Таким образом, использование класса-обёртки может стать решением для тестовой настройки. Вот то, что я только что взломал, без особого рассмотрения и изощренности:

#include <iostream>

class Base {
};

class DerivedA : public Base {
};

class DerivedB : public Base {
};

class DerivedC : public Base {
};

class Test {
public:
void world( DerivedA *instance )
{
std::cout << "DerivedA" << std::endl;
}

void world( DerivedB *instance )
{
std::cout << "DerivedB" << std::endl;
}

void world( Base *instance )
{
std::cout << "Base" << std::endl;
}
};

template<typename T>
class Wrapper
{
public:
Wrapper(T* i) : instance(i)
{
}
~Wrapper()
{
delete instance;
}

void doTest(Test& t)
{
t.world(instance);
}

T* instance;
};int main()
{
Test hello;
Wrapper<Base> a(new Base);
Wrapper<DerivedA> b(new DerivedA);
Wrapper<DerivedB> c(new DerivedB);
Wrapper<DerivedC> d(new DerivedC);

a.doTest(hello);
b.doTest(hello);
c.doTest(hello);
d.doTest(hello);

return 0;
}
3

Другие решения

В вашем примере у вас нет схемы полиморфизма во время выполнения (т. Е. Динамическое связывание). У вас есть перегруженная функция-член, и в разрешении перегрузки компилятор правильно выбирает void world( Base *instance ),

Чтобы получить то, что вы хотите, вы должны применить схему наследования, подобную приведенной ниже:

class Base {
public:
virtual ~Base() {}
virtual void world() const { std::cout << "Base" << std::endl; }
};

class DerivedA : public Base {
public:
virtual ~DerivedA() {}
void world() const { std::cout << "DerivedA" << std::endl; }
};

class DerivedB : public Base {
public:
virtual ~DerivedB() {}
void world() const  { std::cout << "DerivedB" << std::endl; }
};

class DerivedC : public Base {
public:
virtual ~DerivedC() {}
using Base::world;
};

Live Demo

Редактировать:

Чтобы сохранить ваш код в одном месте, вы можете добавить к приведенной выше схеме следующую измененную версию Test учебный класс:

class Test {
public:
void world( DerivedA *instance ) { instance->world(); }
void world( DerivedB *instance ) { instance->world(); }
void world( Base     *instance ) { instance->world(); }
};

Live Demo

К сожалению, разрешение перегрузки происходит во время компиляции, тогда как динамическая диспетчеризация происходит во время выполнения. Таким образом, если вы намеревались для компилятора вывести базовый тип из Base указатель, а затем забрать правую функцию-член из Test класс, это неосуществимо.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector