23

我现在在一堂课上学习 C++,我不太了解纯虚函数。我知道它们稍后在派生类中进行了概述,但是如果您只是要在派生类中定义它,为什么要将其声明为等于 0?

4

8 回答 8

35

简单来说就是把类抽象化,使其不能被实例化,但是子类可以重写纯虚方法,形成一个具体的类。这是在 C++ 中定义接口的好方法。

于 2009-07-01T20:10:47.457 回答
16

这会强制派生类定义函数。

于 2009-07-01T20:12:22.710 回答
8

任何包含纯虚方法的类都是抽象的,也就是说,它不能被实例化。抽象类对于定义子类应该共享的一些核心行为很有用,但允许(实际上,要求)子类单独实现抽象。

一个抽象类的例子:

class Foo {

    // pure virtual, must be implemented by subclasses
    virtual public void myMethod() = 0;

    // normal method, will be available to all subclasses,
    // but *can* be overridden
    virtual public void myOtherMethod();
};

每个方法都是抽象的类可以用作接口,要求所有子类通过实现其中包含的所有方法来符合接口。

接口示例:

class Bar {

    // all method are pure virtual; subclasses must implement
    // all of them
    virtual public void myMethod() = 0;

    virtual public void myOtherMethod() = 0;
};
于 2009-07-01T20:19:20.870 回答
4

C++ 中的纯虚方法基本上是一种无需实现接口即可定义接口的方法。

于 2009-07-01T20:16:45.760 回答
3

要添加到 Steven Sudit 的答案:

“简单来说就是把类抽象化,这样就不能实例化了,但是子类可以重写纯虚方法,形成一个具体的类。这是在C++中定义接口的好方法。”

例如,如果您有一个基类(可能是 Shape),用于定义其派生类可以使用的许多成员函数,但希望防止声明 Shape 的实例并强制用户仅使用派生类(可能是矩形、三角形、五边形等)

RE:上面杰夫的回答

非抽象类可以包含虚成员函数并被实例化。事实上,对于重载成员函数,这是必需的,因为默认情况下 C++ 不会确定变量的运行时类型,但是当使用虚拟关键字定义时,它会确定。

考虑这段代码(注意,为了清楚起见,不包括访问器、修改器、构造器等):

class Person{
  int age;

  public:
    virtual void print(){
      cout << age <<endl;
    }
}

class Student: public Person{
  int studentID

  public:
    void print(){
      cout << age << studentID <<endl;
    }
}

现在运行此代码时:

 Person p = new Student();
 p.print();

如果没有 virtual 关键字,则只会打印年龄,而不是 Student 类应该发生的年龄和学生 ID

(这个例子基于一个非常相似的来自 c++ 的 Java 程序员http://www.amazon.com/Java-Programmers-Mark-Allen-Weiss/dp/013919424X

@Steven Sudit:你是完全正确的,我忽略了包含实际继承,doh!不包括访问器等以使事情更清晰,我现在已经使这一点更加明显。09 年 3 月 7 日:全部固定

于 2009-07-01T20:18:28.890 回答
3

想象一下,我想对几种形状进行建模,并且都有一个明确定义的区域。我决定每个形状都必须继承IShape(“I”表示接口),IShape并将包含一个GetArea()方法:

class IShape {
    virtual int GetArea();
};

现在的问题是:如果该形状不覆盖,我应该如何计算该形状的面积GetArea()?也就是说,最好的默认实现是什么?圆形使用 pi*radius^2,正方形使用 length^2,平行四边形和矩形使用 base*height,三角形使用 1/2 base*height,菱形、五边形、八边形等使用其他公式。

所以我说“如果你是一个形状,你必须定义一种计算面积的方法,但如果我知道那会是什么,那该死的”通过定义纯虚拟方法:

class IShape {
    virtual int GetArea() = 0;
};
于 2009-07-01T20:19:59.670 回答
1

本质上,纯虚拟用于创建接口(类似于 java)。这可以用作两个模块(或类,或其他)之间关于期望什么样的功能的协议,而无需了解其他部分的实现。这使您可以使用相同的界面轻松插入和播放片段,而无需更改正在使用您的界面的其他模块中的任何内容。

例如:

class IStudent
{
    public:
    virtual ~IStudent(){};
    virtual std::string getName() = 0;
};


class Student : public IStudent
{
    public:
    std::string name;
    std::string getName() { return name; };
    void setName(std::string in) { name = in; };
};

class School
{
    public:
    void sendStudentToDetention(IStudent *in) {
        cout << "The student sent to detention is: ";
        cout << in->getName() << endl;
    };
};

int main()
{
    Student student;
    student.setName("Dave");

    School school;
    school.sendStudentToDetention(&student);
return 0;
}

学校不需要知道如何设置学生的姓名,只需要知道如何获取学生的姓名即可。通过为学生提供一个接口来实现和学校使用,两部分之间就学校需要什么功能来执行其工作达成了协议。现在我们可以在不影响学校的情况下随意切换不同的Student类实现(只要我们每次都实现相同的接口)。

于 2009-07-01T20:54:31.283 回答
0

抽象类的想法是您仍然可以使用该类型声明变量(即,它是静态类型),但该变量实际上引用或指向实际的具体类型(动态类型)。

在 C++ 中调用方法时,编译器需要确保该对象支持该方法。

通过声明纯虚函数,您放置了一个“占位符”,编译器可以使用它来表示“哦......我知道这个变量最终引用的任何内容都将接受该调用”,因为实际的具体类型将实现它。但是,您不必提供抽象类型的实现。

如果你没有声明任何东西,那么编译器就没有有效的方法来保证它会被所有子类型实现。

当然,如果你问为什么要让一个类抽象,有很多关于这方面的信息。

于 2009-07-01T20:15:36.837 回答