2014-01-12 6 views
-2

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

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

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

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

struct Base 
{ 
    void foo(); 
}; 

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

в основном:

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

Я думал d.foo() должен работать Base :: Foo(), если не используется ' виртуальная.

+1

Пожалуйста, укажите соответствующий код на C++. Мы не можем понять весь ваш вопрос. –

+3

Почему бы вам не показать * нам код вместо * описания * его? SSCCE (http://sscce.org/) будет идеальным. – NPE

+0

Без кода, непонятно, что вы спрашиваете –

ответ

3

Это не «переопределение» ... и это не обязательно.

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 является действительно a Derived. Все, что он знает, это то, что ptr является Base*.

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

+1

Является ли ваш производный предположительным источником из базы? – Brandon

+0

Да, это :) ..... –

+0

@ Планы на орбите: у меня есть вопрос об этом тоже :) Надеюсь, все нормально: при создании массива базовых объектов вроде этого: 'Базовый массив [2 ] = {производный Obj1, производный Obj2}; ' ** array [0] .foo(); ** запускает базовый foo(), а не производный foo(), даже если он является« виртуальным »в классе Base. , с другой стороны, при создании массива базовых объектов, подобных этому: 'Base * array [2] = {new Derived(), new Derived()};' ** array [0] .foo(); ** запускает Derived foo() ... Могу ли я получить первый вариант работы полиморфный, как второй? – theexplorer

0

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

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.

BTW, используя C++11 лямбда anonymous functions (внутренне реализована в виде closures), что было бы проще и короче.

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

 Смежные вопросы

  • Нет связанных вопросов^_^