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?
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++.
This forces a derived class to define the function.
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;
};
Pure virtual methods in C++ are basically a way to define interfaces without requiring them to be implemented.
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
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;
};
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).
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.
© 2022 - 2024 — McMap. All rights reserved.