Создать объект такого же класса

240
04 июля 2017, 23:11

Как имея указатель на класс A хранящий адрес на объект класса B создать новый объект класса B?

class A {
public:
    A() {cout << "A" << endl;}
    A(const A& a) {cout << "const A&" << endl;}
    virtual ~A() {cout << "~A" << endl;}
};
class B : public A {
public:
    B() { cout << "B" << endl; }
    B(const B& a) { cout << "const B&" << endl;}
    ~B() { cout << "~B" << endl;}
};
template<typename T>
void create(const T& link)
{
    cout << typeid(link).name() << endl;
    T* obj = new T(link);
    cout << typeid(*obj).name() << endl;
}
void main(){
    A* b=new B;
    create(*b);
}

В данном примере typeid(link).name() вернет class B, но созданный объект будет класса A

Answer 1

Предусмотреть это самостоятельно еще на стадии проектирования классов, т.е. завести в свой иерархии классов виртуальный метод clone()

class A {
public:
    A() {cout << "A" << endl;}
    A(const A& a) {cout << "const A&" << endl;}
    virtual ~A() {cout << "~A" << endl;}
    virtual A* clone() const { return new A(*this); }
};
class B : public A {
public:
    B() { cout << "B" << endl; }
    B(const B& a) { cout << "const B&" << endl;}
    ~B() { cout << "~B" << endl;}
    virtual B* clone() const { return new B(*this); }
};
int main()
{
  A *b = new B;
  A *another_b = b->clone();
  ...
}

Разумеется, конкретный тип получающегося в результате объекта - параметр времени выполнения, который не может быть "зафиксирован" на стадии компиляции. Распознать этот тип никакие шаблоны вам помочь не смогут. Если вы "точно знаете", что исходный и клонированный объект имеет тип B (как в данном примере), то приводить указатели к типу B * придется вручную при помощи downcast-ов.

Answer 2

Можно и с шаблонами, но будет чуть сложнее:

using namespace std;
struct Base
{
    Base() { cout << "Base c-tor" << endl; }
    virtual void foo() { cout << "Base::foo" << endl; }
    virtual ~Base() {}
};
struct D1 : public Base
{
    D1() : Base() { cout << "D1 c-tor" << endl; }
    virtual void foo() override { cout << "D1::foo" << endl; }
};
struct D2 : public Base
{
    D2() : Base() { cout << "D2 c-tor" << endl; }
    D2(const D2&) : Base() { cout << "D2 copy c-tor" << endl; }
    virtual void foo() override { cout << "D2::foo" << endl; }
};
struct DD : public D1
{
    DD() : D1() { cout << "DD c-tor" << endl; }
    virtual void foo() override { cout << "DD::foo" << endl; }
};
template <class T> Base* create()
{
    return new T;
}
template <class T> Base* copy(const Base* arg)
{
    const T* t = dynamic_cast<const T*>(arg);
    if (t)
        return new T(*t);
    else
        return new T(); // Здесь Вам решать что делать: бросать исключение, возвращать 0 ил что-то еще
}
int main()
{
    Base* b1 = create<DD>();
    b1->foo();
    Base* b2 = create<D2>();
    b2->foo();
    Base* b3 = create<Base>();
    b3->foo();
    cout << "=================" << endl;
    Base *b4 = copy<D2>(b1); // неудача *b1 - не экземпляр D2
    b4->foo();
    Base *b5 = copy<D2>(b2);
    b5->foo();
    return 0;
}

Вывод:

Base c-tor
D1 c-tor
DD c-tor
DD::foo
Base c-tor
D2 c-tor
D2::foo
Base c-tor
Base::foo
=================
Base c-tor
D2 c-tor
D2::foo
Base c-tor
D2 copy c-tor
D2::foo
READ ALSO
Применение атомарных операций

Применение атомарных операций

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

198
Стандартные библиотеки С++

Стандартные библиотеки С++

Доброго времени суток гуру С++ и не толькоНачал изучать этот замечательный язык по книге 2016 , но, как оказывается, некоторые примеры не совсем...

189
Сделать нормальный выход из чата с++

Сделать нормальный выход из чата с++

Когда один из клиентов чата закрывает чат(закрывает приложение) на сервере начинает лагать его последнее сообщение(отправляться много раз)...

205
SFML SocketSelector::wait() некорректно работает

SFML SocketSelector::wait() некорректно работает

Делаю небольшой мессенджер (протокол TCP)Есть сервер и клиент

233