What are the uses of pure virtual functions in C++?
Asked Answered
R

8

24

I'm learning about C++ in a class right now and I don't quite grok pure virtual functions. I understand that they are later outlined in a derived class, but why would you want to declare it as equal to 0 if you are just going to define it in the derived class?

Rheum answered 1/7, 2009 at 20:7 Comment(4)
For you and the few who voted you up: The textbook didn't explain the WHY; and since I'm sure someone else will Google it, I asked it here. That way someone else can benefit.Rheum
What textbook was that, then? Frankly, the answers here (as is typical for such general questions) are neither particularly good nor accurate. So don't feel you are doing a service by asking questions like this.Merc
you may wonder why you want a base class to be abstract. it is - among other things - to control usage of your class hierarchy, remember when you create classes you not only modeling the problem, you also need to take into account how they will be used in the future and by others.Chibcha
Neil: Some of use don't sit on here all day. Don't think you do this community service by being snarky. Your right, a lot of these are not good answers, but the top one breaks it down to its most base level. SOMEONE else will benefit from that.Rheum
P
36

Briefly, it's to make the class abstract, so that it can't be instantiated, but a child class can override the pure virtual methods to form a concrete class. This is a good way to define an interface in C++.

Proficiency answered 1/7, 2009 at 20:10 Comment(3)
I'd recommend changing: "...a child class can..." to "...a leaf class must...".Joinville
I tried to stay intentionally vague to allow for the possibility of a child that overrides some but not all pure virtual methods, which results in an abstract base class that requires fewer overrides to become concrete. I wouldn't call it a leaf, however, because even a concrete child can have children of its own, and some of those can be abstract. In fact, a class can simultaneously override all previously pure virtual methods while declaring new ones. Given all this, I think it's probably better to leave the original, brief explanation, with this long-winded comment.Proficiency
The issue is probably just one of of terminology. IMHO, a function is only pure virtual if it has not been implemented in one of the derived classes. In otherwords, if a class at any level still has a pure virtual function, then that class is still abstract. Hence my request. But I'd say that these comments probably explain things enough at this point! :)Joinville
R
17

This forces a derived class to define the function.

Redistrict answered 1/7, 2009 at 20:12 Comment(0)
V
8

Any class containing a pure virtual method will be abstract, that is, it cannot be instantiated. Abstract classes are useful for defining some core behavior that subclasses should share, but allowing (in fact, requiring) subclasses to implement the abstract individually.

An example of an abstract class:

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();
};

A class in which every method is abstract can be used as an interface, requiring all subclasses to conform to the interface by implementing all methods contained in it.

An example of an interface:

class Bar {

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

    virtual public void myOtherMethod() = 0;
};
Varuna answered 1/7, 2009 at 20:19 Comment(2)
I think you meant the first sentence to be "Any class containing a pure virtual method"....Panelboard
I would probably add that an Abstract Base Class may contain not only implementations of methods, but data members as well. An interface should have neither. In C++, this is just a convention. In C# or Java, it's a rule.Proficiency
F
4

Pure virtual methods in C++ are basically a way to define interfaces without requiring them to be implemented.

Flighty answered 1/7, 2009 at 20:16 Comment(1)
Correct, more precisely: "a way to force all inheritors follow the defined signature"Darla
P
3

To add to Steven Sudit's answer:

"Briefly, it's to make the class abstract, so that it can't be instantiated, but a child class can override the pure virtual methods to form a concrete class. This is a good way to define an interface in C++."

An example of this would be if you had a base class (perhaps Shape) that you use to define a number of member functions that its derived classes can use, but want to prevent an instance of Shape being declared and force users to use only the derived classes (which may be, Rectangle, Triangle, Pentagon, and so on)

RE: Jeff's answer above

Non-abstract classes can contain virtual member functions and be instantiated. In fact, for overloading member functions this is required as by default C++ doesn't determine the runtime type of a variable, but when defined using th virtual keyword, it will.

Consider this code (note, accessors, mutators, constructors, etc are not included for the sake of clarity):

class Person{
  int age;

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

class Student: public Person{
  int studentID

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

Now when running this code:

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

without the virtual keyword, only the age would be printed, not the age and studentID as is supposed to happen for the Student class

(this example is based on a very similar one from c++ for java programmers http://www.amazon.com/Java-Programmers-Mark-Allen-Weiss/dp/013919424X )

@Steven Sudit: you are completely correct, I neglected to include the actual inheritance, doh! The accessors etc aren't included to keep things clearer, and I've made that more obvious now. 3-7-09: all fixed

Puerperal answered 1/7, 2009 at 20:18 Comment(4)
I believe your example is broken, as it doesn't include inheritance, and there's no way to ever set the values of the private data members. The idea behind it is correct, of course.Proficiency
That's better, but still not quite right: the child class shouldn't have its own age data member.Proficiency
Also, the instantiation at the bottom lacks parentheses around the constructor.Proficiency
@chrris One question. will this line work in c++ ? : "Person p = new Student();". (new operator returns a pointer)Rajab
P
3

Imagine I want to model several kinds of shapes, and all have a well-defined area. I decide that every shape must inherit IShape ("I" for interface), and IShape will include a GetArea() method:

class IShape {
    virtual int GetArea();
};

Now the problem: how should I calculate the area of a shape if that shape doesn't override GetArea()? That is, what is the best default implementation? Circles use pi*radius^2, squares use length^2, parallelograms and rectangles use base*height, triangles use 1/2 base*height, rhombuses, pentagons, octagons, etc. use other formulas.

So I say "if you're a shape you must define a way to calculate the area, but damned if I know what that will be" by defining the method pure virtual:

class IShape {
    virtual int GetArea() = 0;
};
Puccoon answered 1/7, 2009 at 20:19 Comment(2)
Wouldn't GetArea have to be declared virtual in both cases?Proficiency
It needs to be declared virtual in the base class. Thanks for the correction.Puccoon
H
1

Essentially, pure virtuals are used to create an interface (similar to java). This can be used as an agreement between two modules (or classes, or whatever) as to what kind of functionality to expect, without having to know anything about the implementation of the other piece. This allows you to easily plug and play pieces using the same interface without having to change anything in the other module which is using your interface.

For example:

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;
}

The school doesn't need to know how to set a student's name, all it needs to know is how to get the student's name. By providing an interface for Student to implement and the school to use, there's an agreement between the two pieces about what functionality is needed by school to perform its job. Now we can switch in and out different implementations of the Student class all we want without affecting the school (as long as we implement the same interface each time).

Hereditable answered 1/7, 2009 at 20:54 Comment(2)
I would suggest that the "name" data member in Student should be private, or at least protected. I would also recommend passing in the student by reference, not pointer. Finally, a real-world Student class would probably take the name in its constructor.Proficiency
i concur with all of that. those were just oversights when i typed up this example real quick.Hereditable
L
0

The idea with abstract classes is that you can still have a variable declared with that type (i.e., it is the static type), but the variable actually refers or points to an actual concrete type (the dynamic type).

When you invoke a method in C++, the compiler needs to make sure that the method would be supported on that object.

By declaring the pure virtual function, you are putting a "placeholder" that the compiler can use to say "oh... I know that whatever ends up being referred to by this variable will accept that call" because the actual concrete types will implement it. However, you don't have to provide an implementation in the abstract type.

If you didn't declare anything, then the compiler would have no effective way of guaranteeing that it would be implemented by all subtypes.

Of course, if you're asking why you would want to make a class abstract, there's a lot of info around on that.

Lipase answered 1/7, 2009 at 20:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.