Я хотел бы видеть печать двух объектов из двух разных производных классов, и ключом к этому является приведение объекта к производному классу после его определения как базового. Вот код:
#include <iostream>
#include "memory"
using namespace std;
template<class T>
class Base
{
public:
Base() {};
~Base() {};
void Print()
{
std::cout << "Print from Base" << std::endl;
}
};
class Derived1: public Base<int>
{
public:
Derived1() {}
void Print()
{
std::cout << "Print from Derived1" << std::endl;
}
};
class Derived2: public Base<int>
{
public:
Derived2() {}
void Print()
{
std::cout << "Print from Derived2"<< std::endl;
}
};
class user
{
public:
user();
user(int type)
:m_type(type)
{
switch(type) // change should be done here?
{
case 1:
m_ptr = make_unique<Derived1>(); // m_ptr still base? why not derived
break;
case 2:
m_ptr = make_unique<Derived2>();;
break;
default:
break;
}
}
~user() {};
void UserPrint()
{
m_ptr->Print();
}
private:
std::unique_ptr<Base<int>> m_ptr;
int m_type;
};
int main()
{
user a(1);
user b(2);
a.UserPrint();
b.UserPrint();
return 0;
}
Я ожидаю увидеть
Print from Derived1
Print from Derived2
но вместо этого я вижу
Print from Base
Print from Base
Как изменить код, чтобы он работал? Я бы предпочел изменить конструктор user(int type)
.
@ user4581301 Я полностью с тобой согласен :D
Совет по упрощению: class Base { public: void Print() { std::cout << "Print from Base\n"; } };
-- Нет необходимости иметь шаблон и нет необходимости определять ничего не делающий конструктор/деструктор. Чтобы сделать это еще проще, замените class
на struct
и отбросьте public:
. Хотя эти детали могут иметь ценность в реальном коде, в этом примере они отвлекают внимание.
Я думаю, что у вас есть некоторое недопонимание относительно переопределения методов в C++, потому что вам не хватает виртуальных ключевых слов в (предполагаемых) виртуальных методах:
#include <iostream>
#include "memory"
using namespace std;
template<class T>
class Base
{
public:
Base() {};
~Base() {};
virtual void Print()
{
std::cout << "Print from Base" << std::endl;
}
};
class Derived1: public Base<int>
{
public:
Derived1() {}
void Print() override
{
std::cout << "Print from Derived1" << std::endl;
}
};
class Derived2: public Base<int>
{
public:
Derived2() {}
void Print() override
{
std::cout << "Print from Derived2"<< std::endl;
}
};
class user
{
public:
user();
user(int type)
:m_type(type)
{
switch(type) // change should be done here?
{
case 1:
m_ptr = make_unique<Derived1>(); // m_ptr still base? why not derived
break;
case 2:
m_ptr = make_unique<Derived2>();;
break;
default:
break;
}
}
~user() {};
void UserPrint()
{
m_ptr->Print();
}
private:
std::unique_ptr<Base<int>> m_ptr;
int m_type;
};
int main()
{
user a(1);
user b(2);
a.UserPrint();
b.UserPrint();
return 0;
}
Обратите внимание на использование ключевого слова override
в производных Print
. virtual
является обязательным в базовом классе для работы переопределения, но override
выдает ошибки, если метод должен переопределять, но по той или иной причине этого не делает. Например, простая опечатка: print
не отменяет Print
. Упс. Но если print
помечен override
, компилятор обнаружит ошибку.
Если вы не говорите нам ничего, ваша жизнь станет намного проще, если вы сделаете метод
Print
виртуальным.