如果一个函数被定义为虚函数,它究竟意味着什么?它与纯虚函数是相同的吗?
当前回答
virtual关键字赋予c++支持多态的能力。当你有一个指向某个类的对象的指针时,例如:
class Animal
{
public:
virtual int GetNumberOfLegs() = 0;
};
class Duck : public Animal
{
public:
int GetNumberOfLegs() { return 2; }
};
class Horse : public Animal
{
public:
int GetNumberOfLegs() { return 4; }
};
void SomeFunction(Animal * pAnimal)
{
cout << pAnimal->GetNumberOfLegs();
}
在这个(愚蠢的)示例中,GetNumberOfLegs()函数根据所调用对象的类返回适当的数字。
现在,考虑函数“SomeFunction”。它不关心传递给它的是什么类型的animal对象,只要它是从animal派生的。编译器会自动地将任何Animal派生类强制转换为Animal,因为它是一个基类。
如果我们这样做:
Duck d;
SomeFunction(&d);
它会输出'2'。如果我们这样做:
Horse h;
SomeFunction(&h);
它会输出'4'。我们不能这样做:
Animal a;
SomeFunction(&a);
因为它不会编译,因为GetNumberOfLegs()虚函数是纯的,这意味着它必须通过派生类(子类)来实现。
纯虚函数主要用于定义:
A)抽象类
这些是基类,你必须从它们中派生出来,然后实现纯虚函数。
b)接口
这些是“空”类,其中所有的函数都是纯虚的,因此你必须派生然后实现所有的函数。
其他回答
虚函数是在基类中声明并由派生类重新定义的成员函数。虚函数是按继承顺序分层的。 当派生类不重写虚函数时,将使用在其基类中定义的函数。
纯虚函数是指相对于基类不包含任何定义的虚函数。 它在基类中没有实现。任何派生类都必须重写此函数。
“Virtual”意味着该方法可以在子类中重写,但在基类中有一个可直接调用的实现。“纯虚拟”意味着它是一个没有直接可调用实现的虚拟方法。这样的方法必须在继承层次结构中至少重写一次——如果一个类有任何未实现的虚方法,该类的对象就不能被构造,编译就会失败。
@夸克指出,纯虚拟方法可以有一个实现,但由于纯虚拟方法必须被覆盖,所以不能直接调用默认的实现。下面是一个带默认值的纯虚方法的例子:
#include <cstdio>
class A {
public:
virtual void Hello() = 0;
};
void A::Hello() {
printf("A::Hello\n");
}
class B : public A {
public:
void Hello() {
printf("B::Hello\n");
A::Hello();
}
};
int main() {
/* Prints:
B::Hello
A::Hello
*/
B b;
b.Hello();
return 0;
}
根据注释,编译是否失败是特定于编译器的。至少在GCC 4.3.3中,它不会编译:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
输出:
$ g++ -c virt.cpp
virt.cpp: In function ‘int main()’:
virt.cpp:8: error: cannot declare variable ‘a’ to be of abstract type ‘A’
virt.cpp:1: note: because the following virtual functions are pure within ‘A’:
virt.cpp:3: note: virtual void A::Hello()
来自维基百科的虚拟功能 ...
在面向对象编程中,在c++和Object Pascal等语言中,虚函数或虚方法是一种可继承和可覆盖的函数或方法,可以方便地进行动态分派。这个概念是面向对象编程(OOP)的(运行时)多态性部分的重要组成部分。简而言之,虚函数定义了要执行的目标函数,但在编译时可能不知道目标。
与非虚函数不同,当虚函数被重写时,派生最多的版本将用于类层次结构的所有级别,而不仅仅是创建它的级别。因此,如果基类的一个方法调用虚方法,将使用派生类中定义的版本,而不是基类中定义的版本。
这与非虚函数相反,非虚函数仍然可以在派生类中被重写,但“新”版本只会被派生类及其以下类使用,但根本不会改变基类的功能。
而. .
纯虚函数或纯虚方法是一种虚函数,如果派生类不是抽象的,则需要由派生类实现。
当纯虚方法存在时,类是“抽象的”,不能单独实例化。相反,必须使用实现纯虚方法的派生类。纯虚类根本没有在基类中定义,因此派生类必须定义它,否则派生类也是抽象的,不能实例化。只有没有抽象方法的类才能被实例化。
虚类提供了一种重写基类功能的方法,而纯虚类则需要这种方法。
在c++类中,virtual是一个关键字,它表示一个方法可以被子类重写(即由子类实现)。例如:
class Shape
{
public:
Shape();
virtual ~Shape();
std::string getName() // not overridable
{
return m_name;
}
void setName( const std::string& name ) // not overridable
{
m_name = name;
}
protected:
virtual void initShape() // overridable
{
setName("Generic Shape");
}
private:
std::string m_name;
};
在这种情况下,子类可以覆盖initShape函数来做一些专门的工作:
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
术语纯虚指的是需要由子类实现而基类还没有实现的虚函数。通过使用virtual关键字并在方法声明的末尾添加a =0,可以将一个方法指定为纯虚拟方法。
所以,如果你想让Shape::initShape纯虚拟,你会做以下事情:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
通过向类中添加纯虚方法,可以使类成为抽象基类 这对于将接口与实现分离非常方便。
virtual关键字赋予c++支持多态的能力。当你有一个指向某个类的对象的指针时,例如:
class Animal
{
public:
virtual int GetNumberOfLegs() = 0;
};
class Duck : public Animal
{
public:
int GetNumberOfLegs() { return 2; }
};
class Horse : public Animal
{
public:
int GetNumberOfLegs() { return 4; }
};
void SomeFunction(Animal * pAnimal)
{
cout << pAnimal->GetNumberOfLegs();
}
在这个(愚蠢的)示例中,GetNumberOfLegs()函数根据所调用对象的类返回适当的数字。
现在,考虑函数“SomeFunction”。它不关心传递给它的是什么类型的animal对象,只要它是从animal派生的。编译器会自动地将任何Animal派生类强制转换为Animal,因为它是一个基类。
如果我们这样做:
Duck d;
SomeFunction(&d);
它会输出'2'。如果我们这样做:
Horse h;
SomeFunction(&h);
它会输出'4'。我们不能这样做:
Animal a;
SomeFunction(&a);
因为它不会编译,因为GetNumberOfLegs()虚函数是纯的,这意味着它必须通过派生类(子类)来实现。
纯虚函数主要用于定义:
A)抽象类
这些是基类,你必须从它们中派生出来,然后实现纯虚函数。
b)接口
这些是“空”类,其中所有的函数都是纯虚的,因此你必须派生然后实现所有的函数。
推荐文章
- c++中有最大数组长度限制吗?
- 什么是“参数依赖查找”(又名ADL,或“Koenig查找”)?
- 公共朋友交换成员函数
- 如何在Go中使用c++
- 自定义c++分配器的引人注目的例子?
- RAII和c++中的智能指针
- 如何构建和使用谷歌TensorFlow c++ api
- 断言是邪恶的吗?
- 下面这些短语在c++中是什么意思:0 -,default-和value-initialization?
- 在STL地图中,使用map::insert比[]更好吗?
- C++ Linux的想法?
- 如何为Fedora安装g++ ?
- Std::cin输入空格?
- c++标准是否要求iostreams的性能很差,或者我只是在处理一个糟糕的实现?
- gcc在哪里查找C和c++头文件?