аргументы по умолчанию в основном синтаксический сахар и получить определяется во время компиляции. С другой стороны, виртуальная отправка - это функция времени выполнения. Вероятно, было бы наименее удивительно, если бы этот параметр по умолчанию был выбран, который был определен вместе с функцией, которая фактически вызвана, но это невозможно (по крайней мере, без дополнительных служебных служебных программ) по причине, указанной выше.
Поэтому параметр по умолчанию выбирается компилятором, используя статический объект , на который вызывается функция-член. Давайте посмотрим пример.
#include <iostream>
#include <memory>
class Base
{
public:
virtual void
f(int a, int b = 1)
{
std::cout << "Base: a = " << a << ", b = " << b << "\n";
}
};
class Derived : public Base
{
public:
virtual void
f(int a = 1, int b = 2) override
{
std::cout << "Derived: a = " << a << ", b = " << b << "\n";
}
};
int
main()
{
std::unique_ptr<Base> base_as_base {new Base {}};
std::unique_ptr<Base> derived_as_base {new Derived {}};
std::unique_ptr<Derived> derived_as_derived {new Derived {}};
base_as_base->f(0); // Base: a = 0, b = 1
derived_as_base->f(0); // Derived: a = 0, b = 1
// derived_as_base->f(); // compiler error
derived_as_derived->f(0); // Derived: a = 0, b = 2
derived_as_derived->f(); // Derived: a = 1, b = 2
}
Я согласен с тем, что это сбивает с толку. Пожалуйста, не пишите такой код. К счастью, есть простой способ обхода проблемы. Помимо использования параметров по умолчанию, мы можем использовать идиому под названием не виртуальных интерфейсов. Виртуальная функция сделана protected
и не задана никаких параметров по умолчанию. Затем он называется косвенно функцией не virtual
из базового класса. Эта функция может иметь все параметры по умолчанию, определенные в одном месте.
#include <iostream>
#include <memory>
class Base
{
public:
void
f(int a, int b = 1)
{
this->impl(a, b);
}
protected:
virtual void
impl(int a, int b)
{
std::cout << "Base: a = " << a << ", b = " << b << "\n";
}
};
class Derived : public Base
{
protected:
virtual void
impl(int a, int b) override
{
std::cout << "Derived: a = " << a << ", b = " << b << "\n";
}
};
int
main()
{
std::unique_ptr<Base> base_as_base {new Base {}};
std::unique_ptr<Base> derived_as_base {new Derived {}};
std::unique_ptr<Derived> derived_as_derived {new Derived {}};
base_as_base->f(0); // Base: a = 0, b = 1
derived_as_base->f(0); // Derived: a = 0, b = 1
derived_as_derived->f(0); // Derived: a = 0, b = 1
}
Ну, вы попробовали? Это вопрос минут ... – zegkljan
@ JanZegklitz Я согласен с тем, что вы можете легко попробовать это, если знаете, что попробовать, но это * - это запутанная ситуация, и я думаю, что ответ, объясняющий, что происходит, может быть полезен для многие. В конце концов, «я попробовал это с моей версией моего компилятора, и это произошло» не очень хорошая мера для того, как что-то действительно работает на C++. – 5gon12eder