Вот мой код,
#include<iostream>
#include<string>
using namespace std;
class TestClass
{
public:
virtual void test(string st1, string st2);
};
class ExtendedTest: public TestClass
{
public:
virtual void test(string st1, string st2);
};
void TestClass::test(string st1, string st2="st2")
{
cout << st1 << endl;
cout << st2 << endl;
}
void ExtendedTest::test(string st1, string st2="st2")
{
cout << "Extended: " << st1 << endl;
cout << "Extended: " << st2 << endl;
}
void pass(TestClass t)
{
t.test("abc","def");
}int main()
{
ExtendedTest et;
pass(et);
return 0;
}
Когда я запускаю код, вызывается метод («тест») базового класса.
Но я ожидаю, что метод child вызывается, потому что я указал методы как виртуальную функцию.
Тогда как я могу заставить метод дочернего класса быть вызванным? Спасибо.
void pass(TestClass t)
{
t.test("abc","def");
}
Когда вы делаете это, объект, который вы передаете, получает нарезанный в TestClass
и его личность потеряна, так что теперь он ведет себя как TestClass
и вызывает метод соответственно.
Чтобы исправить это, вы хотите пройти t
по ссылке, как предложено @Nick, или (не рекомендуется) по указателю. Теперь он сохранит свою идентичность и вызовет соответствующую функцию, пока test
помечен виртуальным
Редактировать: исправлено сращено -> нарезано .. слишком много биошока ..
Вам нужно изменить параметр для ссылки (или указатель)
void pass(TestClass &t)
Таким образом, оригинальный объект будет использоваться.
Как отмечалось выше, это результат «нарезки». Конкретные детали того, что происходит, заключаются в следующем:
Когда аргументы передаются по значению, копия аргумента передается функции. Когда это происходит, новый объект создается путем вызова конструктора копирования.
Для вашего примера конструктор копирования имеет следующую подпись:
TestClass::TestClass(const TestClass&);
Итак, что действительно происходит, это что-то вроде следующего (опять же, для вашего примера):
ExtendedTest et();
pass(et);
{ // entering scope of pass function ...
TestClass t = TestClass(t_orig); // inserted by the compiler
// evaluation of pass function ...
// ...
} // leaving scope of pass function, t is destroyed.
Очевидно, что, поскольку переменная t создается как TestClass, любые вызовы функций-членов будут происходить из TestClass (а не ExtendedTest).
В заключение, вы должны всегда объявлять виртуальные деструкторы при использовании наследования. Это позволит избежать нарезки, когда объекты уничтожены.