2010-06-16 3 views
18

Мне задали этот сумасшедший вопрос. Я был вне своего ума.Вопрос о виртуальных функциях в C++

Можно ли вызвать метод в базовом классе, объявленный как виртуальный, с использованием указателя базового класса, который указывает на объект производного класса?

Возможно ли это?

+9

Вы могли бы хотеть получить одну из вводных книг из [The Definitive C++ Book Guide and List] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). –

+2

@James: Я думаю, он спрашивает, можете ли вы назвать 'base :: foo()' not 'производным :: foo()' using 'p', если' p' является 'base *' и указывает на 'производный ' –

+0

@ Джон: Итак? Тем не менее Джеймс прав. – sbi

ответ

49

Если вы пытаетесь вызвать виртуальный метод из указателя базового класса, да.

Это полиморфизм.

Если вы спрашиваете, указав базовый класс на производный класс, можете ли вы вызвать метод базового класса, который переопределяется производным классом? Да, это возможно, явно обзорного имя базового класса:

basePtr->BaseClass::myMethod();

+4

Полиморфизм - это то, где он классифицирует метод производного класса, потому что метод является виртуальным в базовом классе. Фактически вызов метода базового класса с помощью указателя на базу, даже если метод базового класса был переопределен, обходит полиморфизм, который отличается. –

+1

На самом деле все наоборот. Вопрос заключается в том, чтобы вызвать виртуальный метод базового класса, когда объект имеет производный тип, который переопределяет метод. – JaredPar

+5

Hrm, вопрос, как написано, сбивает с толку. – Alan

10

Вы имеете в виду что-то вроде этого. (Где pBase имеет тип указателя на базу, но заостренный-объекта на самом деле типа Derived, который является производным от Base.)

pBase->Base::method(); 

Да, это возможно.

16

Try:

class A   { virtual void foo(); } 
class B : public A { virtual void foo(); } 

A *b = new B(); 
b->A::foo(); 
+4

На самом деле, я думаю, что это должно быть «A * b = new B()» вместо «B * b = new B()», чтобы следовать этому вопросу. – Luca

+1

Да, должно. –

-1

Нет, не в чистом виде. Но да. Вы должны сделать некоторые манипуляции с указателями, получить указатель на vtable и сделать вызов. но это не точно указатель на базовый класс, но некоторые умные манипуляции с указателями. Другим подходом является использование оператора разрешения области действия в базовом классе.

+0

C++ напрямую поддерживает то, что задает вопрос. 'base-> base :: function()' будет делать трюк. Здесь нет необходимости в vtable hackery. –

+2

Перечитайте ваше сообщение. «оператор разрешения области» не является «другим подходом». Это единственный подход, который вы должны учитывать. –

+0

Согласен. Разрешение рамки - это способ. –

10

Да - вы должны указать полное имя, хотя:

#include <iostream> 

struct base { 
    virtual void print() { std::cout << "Base"; } 
}; 

struct derived : base { 
    virtual void print() { std::cout << "Derived"; } 
}; 

int main() { 
    base *b = new derived; 
    b->base::print(); 
    delete b; 
    return 0; 
} 
5

Если я правильно понял вопрос правильно, у вас есть

class B 
{ 
public: 
    virtual void foo(); 
}; 

class D: public B 
{ 
public: 
    virtual void foo(); 
} 

B* b = new D; 

И вопрос, вы можете позвонить B::foo().Ответ: Да, с помощью

b->B::foo() 
0
class B 
{ 
public: 
    virtual void foo(); 
}; 

class D: public B 
{ 
public: 
    virtual void foo(); 
} 

B* b = new D; 

Попробуйте позвонить

(*b).foo() 

вызывать функцию базового класса Foo

+0

Вы уверены, что это вызовет функцию базового класса foo? Вы проверили это? – Vijay

+0

Было моим общим предположением, что (* b) в конечном итоге будет иметь правильный объект, но при компиляции и запуске я обнаружил, что это не так. Он по-прежнему вызывает производную функцию. Это создало путаницу и для меня, что в чем разница между (* b) .foo() и B b1 = * b; b1.foo() – Pardeep

0
class B { 
    public: virtual void foo(); 
}; 

class D: public B { 
    public: virtual void foo() 
    { 
     B::foo(); 
    }; 
} 

B* b = new D; 

Решения:

  1. b->foo();
  2. b->B::foo()

  3. ИЛИ не отменяют/определить Foo() в производном классе D и вызовите b-> Foo()

  4. B objb = *b; objb.foo() ; // this is object slicing and not (*b).foo() as in one of the previous answers

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