Переопределение функций в C ++ работает без «виртуального»

У меня есть класс, который содержит некоторые функции (не виртуальные), и еще 2 класса публично наследуют этот класс. В обоих подклассах я переопределяю одну и ту же функцию базового класса.

После создания объектов всех трех классов в main (расположенных в одном и том же файле) я вызываю исходную функцию с объектом baseclass и переопределенные функции с объектами производного класса.

Я ожидал, что все 3 вызова функции запустят исходную функцию из базового класса (так как я нигде не использовал «виртуальный» в коде), но я фактически заставляю каждую версию этой функции работать в соответствии с классом, в котором она была определены (3 разных варианта).

У меня есть классы Base & Получается следующим образом:

struct Base
{
void foo();
};

struct Derived : Base
{
void foo();
};

в основном:

int main()
{
Derived d;
d.foo();
}

Я думал, что d.foo () должен запускать Base :: foo (), если не используется ‘virtual’.

0

Решение

Это не «переопределение» … и это не должно быть.

struct Base
{
void foo();
};

struct Derived : Base
{
void foo();
};

int main()
{
Derived d;
d.foo();
}

Если я вас правильно понимаю, то вы ожидали, что это исполнится Base::foo()потому что функции не являются виртуальными и, следовательно, одна не переопределяет другую.

Но здесь вы не нужна виртуальная отправка: правила наследования просто утверждают, что вы получите правильную функцию для типа объекта, на котором вы ее запускаете.

Когда вам нужна виртуальная диспетчеризация / переопределение, это немного другой случай: это когда вы используете косвенность:

int main()
{
Base* ptr = new Derived();
ptr->foo();
delete ptr;
}

В приведенном фрагменте результат будет Base::foo() называется, потому что выражение ptr->foo() не знает что *ptr является действительно Derived, Все, что он знает, это то, что ptr это Base*,

Это где добавление virtual (и при этом сделать одну функцию переопределение другой) заставляет волшебство случиться.

6

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

Вы не можете переопределить то, что не является виртуальным. Не виртуальные функции-члены отправляются статически в зависимости от типа объекта экземпляра.

0

Вы можете обмануть, «переопределив» функцию, сделав ее встроенной функцией, вызывающей что-то косвенно. Что-то вроде (в C ++ 03)

 class Foo;
typedef int foo_sig_t (Foo&, std::string&);
class Foo {
foo_sig_t *funptr;
public:
int do_fun(std::string&s) { return funptr(*this,s); }
Foo (foo_sig_t* fun): funptr(fun) {};
~Foo () { funptr= NULL; };
// etc
};

class Bar : public Foo {
static int barfun(Bar&, std::string& s) {
std::cout << s << std::endl;
return (int) s.size();
};
public:
Bar () : Foo(reinterpret_cast<foo_sig_t*>)(&barfun)) {};
// etc...
};

и позже:

  Bar b;
int x=b.do_fun("hello");

Официально это не перегружает виртуальную функцию, но выглядит очень близко к ней. Однако по моему выше Foo пример каждого Foo экземпляр имеет свой funptr, который не обязательно является общим для класса. Но все Bar экземпляры разделяют так же funptr указывая на то же самое barfun,

Кстати, используя C ++ 11 лямбда анонимные функции (внутренне реализовано как укупорочные), это было бы проще и короче.

Конечно, виртуальные функции в общем случае фактически реализуются с помощью аналогичного механизма: объекты (с некоторыми virtual материал) неявно начать со скрытого поля (возможно, «по имени» _vptr) давая виртуальные таблицы (или таблица виртуальных методов).

0
По вопросам рекламы [email protected]