我是C++的新手。
有人能告诉我c++中的方法重写和虚函数概念的区别吗?
虚函数的功能可以在其派生类中重写。在派生类中重新定义函数称为函数重写。
为什么我们实际上有虚拟函数呢?
发布于 2010-02-11 10:31:32
抽象
在本文中,我们讨论C++中的虚函数。第0部分解释了如何声明和覆盖虚函数。第一部分试图(也许失败了)解释虚拟函数是如何实现的。第二部分是一个示例程序,它使用了在第0部分和第1部分中定义的示例类。第三部分是每个虚拟函数多态性教程中给出的经典动物示例。
第0部分
当且仅当类的方法声明为虚时,才称其为虚虚方法。
class my_base
{
public:
void non_virtual_test() { cout << 4 << endl; } // non-virtual
virtual void virtual_test() { cout << 5 << endl; } // virtual
};(当然,我假设程序员以前没有做过类似#define virtual的事情。)
重新声明并重新实现其基类之一的非虚方法的类称为重载该方法。如果一个类重新声明并重新实现了它的一个基类的虚方法,那么这个类就被称为override那个方法。
class my_derived : public my_base
{
public:
void non_virtual_test() { cout << 6 << endl; } // overloaded
void virtual_test() { cout << 7 << endl; } // overriden
};第一部分
当编译器检测到类具有虚方法时,它会自动向类的内存布局添加一个虚方法表(也称为vtable)。结果与编译此代码所生成的结果类似:
class my_base
{
//<vtable>
// The vtable is actually a bunch of member function pointers
protected:
void (my_base::*virtual_test_ptr)();
//</vtable>
// The actual implementation of the virtual function
// is hidden from the rest of the program.
private:
void virtual_test_impl() { cout << 5 << endl; }
// Initializing the real_virtual_test pointer in the vtable.
public:
my_base() : virtual_test_ptr(&my_base::virtual_test_impl) {}
public:
void non_virtual_test() { cout << 4 << endl; }
// The interface of the virtual function is a wrapper
// around the member function pointer.
inline void virtual_test() { *virtual_test_ptr(); }
};当编译器检测到类重写了虚方法时,它会替换vtable中与其相关联的项。结果与编译此代码所生成的结果类似:
class my_derived : public my_base
{
// The actual implementation of the virtual function
// is hidden from the rest of the program.
private:
void virtual_test_impl() { cout << 7 << endl; }
// Initializing the real_virtual_test pointer in the vtable.
public:
my_derived() : virtual_test_ptr(&my_derived::virtual_test_impl) {}
public:
void non_virtual_test() { cout << 6 << endl; }
};第二部分
现在很清楚虚函数是使用vtable实现的,vtable只是一堆函数指针,下面的代码应该很清楚:
#include <iostream>
using namespace std;
class my_base
{
public:
void non_virtual_test() { cout << 4 << endl; }
virtual void virtual_test() { cout << 5 << endl; }
};
class my_derived : public my_base
{
public:
void non_virtual_test() { cout << 6 << endl; }
void virtual_test() { cout << 7 << endl; }
}
int main()
{
my_base* base_obj = new my_derived();
// This outputs 4, since my_base::non_virtual_test() gets called,
// not my_derived::non_virtual_test().
base_obj->non_virtual_test();
// This outputs 7, since the vtable pointer points to
// my_derived::virtual_test(), not to my_base::virtual_test().
base_obj->virtual_test();
// We shall not forget
// there was an object that was pointed by base_obj
// who happily lived in the heap
// until we killed it.
delete base_obj;
return 0;
}第三部分
因为没有动物的虚拟函数示例是完整的……
#include <iostream>
using namespace std;
class animal
{
public:
virtual void say_something()
{ cout << "I don't know what to say." << endl
<< "Let's assume I can growl." << endl; }
/* A more sophisticated version would use pure virtual functions:
*
* virtual void say_something() = 0;
*/
};
class dog : public animal
{
public:
void say_something() { cout << "Barf, barf..." << endl; }
};
class cat : public animal
{
public:
void say_something() { cout << "Meow, meow..." << endl; }
};
int main()
{
animal *a1 = new dog();
animal *a2 = new cat();
a1->say_something();
a2->say_something();
}发布于 2010-02-11 01:35:47
虚函数/方法只是一个函数,它的行为可以通过重新定义函数的工作方式(使用相同的签名)在子类(或C++术语中的派生类)中被覆盖。
想一想一个具有说话功能的基类哺乳动物。这个函数是空的,只是简单地告诉我们哺乳动物是如何说话的。当您从这个类继承时,您可以重写speak方法,这样狗就会发出"Arf Arf!“猫就会发出“嘟嘟声”。
你的问题似乎是问有什么区别,嗯,没有,因为使用虚函数可以覆盖这些函数的行为。你可能想知道重写函数和重载函数之间的区别。
重载函数意味着创建一个名称相同但参数不同的函数,即不同数量和类型的参数。以下是IBM's site中有关C++中重载的说明
重载(仅限C++)如果为同一范围内的函数名或运算符指定了多个定义,则已重载了该函数名或运算符。重载函数和运算符分别在重载函数(仅限C++)和重载运算符(仅限C++)中描述。
重载声明是在相同作用域中使用与先前声明的声明相同的名称声明的声明,只是这两个声明具有不同的类型。
如果调用重载函数名或运算符,编译器将通过将用于调用函数或运算符的参数类型与定义中指定的参数类型进行比较,来确定要使用的最合适的定义。选择最合适的重载函数或运算符的过程称为重载解析,如重载解析(仅限C++)中所述。
对于需要虚函数的情况,这篇博客文章给出了一个很好的理由:http://nrecursions.blogspot.in/2015/06/so-why-do-we-need-virtual-functions.html
发布于 2010-02-11 04:25:45
对于多态,函数覆盖和virtual函数之间的区别变得很重要。特别是在使用指向基类的引用或指针时。
基础设置
在C++中,任何派生类都可以传递给需要基类对象的函数。(另请参阅Slicing和LSP)。给定:
struct Base_Virtual
{
virtual void some_virtual_function();
};
struct Base_Nonvirtual
{
void some_function();
};
void Function_A(Base_Virtual * p_virtual_base);
void Function_B(Base_Nonvirtual * p_non_virtual_base);在上面的代码中,有两个基类,一个声明一个虚方法,另一个声明一个非虚函数。
声明了两个函数,它们需要指向各自基类的指针。
派生类
现在让我们测试一下多态性,特别是virtual和非虚(覆盖方法)。结构:
struct Derived_From_Virtual
: public Base_Virtual
{
void some_virtual_function(); // overrides Base_Virtual::some_virtual_function()
};结构Derived_From_Nonvirtual :公共Base_Nonvirtual { void some_function();}
根据C++语言,我可以将指向Derived_From_Virtual的指针传递给Function_A,因为Derived_From_Virtual继承自Base_Virtual。我还可以将指向Derived_From_Nonvirtual的指针传递给Function_B。
virtual和overriding之间的区别
Base_Virtual中的virtual修饰符告诉编译器Function_A将使用Derived_From_Virtual::some_virtual_function()而不是Base_Virtual中的方法。这是因为方法是虚的,最终的定义可能驻留在将来的类或派生类中。实际的定义是在包含该定义的最派生类中使用该方法。
当将指向Derived_From_Nonvirtual的指针传递给Function_B时,编译器将指示函数使用基类Base_Nonvirtual::some_function()的方法。派生类中的some_function()方法是独立于基类的、不相关的方法。
virtual和覆盖之间的主要区别在于多态。
https://stackoverflow.com/questions/2238928
复制相似问题