Question

Let me start by telling that I understand how virtual methods work (polymorphism, late-binding, vtables).

My question is whether or not I should make my method virtual. I will exemplify my dilemma on a specific case, but any general guidelines will be welcomed too.

The context:

I am creating a library. In this library I have a class CallStack that captures a call stack and then offers vector-like access to the captured stack frames. The capture is done by a protected method CaptureStack. This method could be redefined in a derived class, if the users of the library wish to implement another way to capture the stack. Just to be clear, the discussion to make the method virtual applies only to some methods that I know can be redefined in a derived class (in this case CaptureStack and the destructor), not to all the class methods.

Throughout my library I use CallStack objects, but never exposed as pointers or reference parameters, thus making virtual not needed considering only the use of my library.

And I cannot think of a case when someone would want to use CallStack as pointer or reference to implement polymorphism. If someone wants to derive CallStack and redefine CaptureStack I think just using the derived class object will suffice.

Now just because I cannot think polymorphism will be needed, should I not use virtual methods, or should I use virtual regardless just because a method can be redefined.


Example how CallStack can be used outside my library:

if (error) {
  CallStack call_stack; // the constructor calls CaptureStack
  for (const auto &stack_frame : call_stack) {
    cout << stack_frame << endl;
  }
}

A derived class, that redefines CaptureStack could be use in the same manner, not needing polymorphism:

if (error) {
  // since this is not a CallStack pointer / reference, virtual would not be needed.
  DerivedCallStack d_call_stack; 
  for (const auto &stack_frame : d_call_stack) {
    cout << stack_frame << endl;
  }
}
Was it helpful?

Solution 2

When deciding whether you need a virtual function or not, you need to see if deriving and overriding the function changes the expected behavior/functionality of other functions that you're implementing now or not.

If you are relying on the implementation of that particular function in your other processes of the same class, like another function of the same class, then you might want to have the function as virtual. But if you know what the function is supposed to do in your parent class, and you don't want anybody to change it as far as you're concerned, then it's not a virtual function.

Or as another example, imagine somebody derives a class from you implementation, overrides a function, and passes that object as casted to the parent class to one of your own implemented functions/classes. Would you prefer to have your original implementation of the function or you want them to have you use their own overriden implementation? If the latter is the case, then you should go for virtual, unless not.

OTHER TIPS

If your library saves the call stack during the constructor then you cannot use virtual methods.

This is C++. One thing people often get wrong when coming to C++ from another language is using virtual methods in constructors. This never works as planned.

C++ sets the virtual function table during each constructor call. That means that functions are never virtual when called from the constructor. The virtual method always points to the current class being constructed.

So even if you did use a virtual method to capture the stack the constructor code would always call the base class method.

To make it work you'd need to take the call out of the constructor and use something like:

CallStack *stack = new DerivedStack;
stack.CaptureStack();

None of your code examples show a good reason to make CaptureStack virtual.

It's not clear to me where CallStack is being called. From your examples, it looks like you're using the template method pattern, in which the basic functionality is implemented in the base class, but customized by means of virtual functions (normally private, not protected) which are provided by the derived class. In this case (as Peter Bloomfield points out), the functions must be virtual, since they will be called from within a member function of the base class; thus, with a static type of CallStack. However: if I understand your examples correctly, the call to CallStack will be in the constructor. This will not work, as during construction of CallStack, the dynamic type of the object is CallStack, and not DerivedCallStack, and virtual function calls will resolve to CallStack.

In such a case, for the use cases you describe, a solution using templates may be more appropriate. Or even... The name of the class is clear. I can't think of any reasonable case where different instances should have different means of capturing the call stack in a single program. Which suggests that link time resolution of the type might be appropriate. (I use the compilation firewall idiom and link time resolution in my own StackTrace class.)

My question is whether or not I should make my method virtual. I will exemplify my dilemma on a specific case, but any general guidelines will be welcomed too.

Some guidelines:

  • if you are unsure, you should not do it. Lots of people will tell you that your code should be easily extensible (and as such, virtual), but in practice, most extensible code is never extended, unless you make a library that will be used heavily (see YAGNI principle).

  • you can use encapsulation in place of inheritance and type polymorphism (templates) as an alternative to class hierarchies in many cases (e.g. std::string and std::wstring are not two concrete implementations of a base string class and they are not inheritable at all).

  • if (when you are designing your code/public interfaces) you realize you have more than one class that "is an" implementation of another classes' interface, then you should use virtual functions.

You should almost certainly declare the method as virtual.

The first reason is that anything in your base class which calls CaptureStack will be doing so through a base class pointer (i.e. the local this pointer). It will therefore call the base class version of the function, even though a derived class masks it.

Consider the following example:

class Parent
{
public:
    void callFoo()
    {
        foo();
    }

    void foo()
    {
        std::cout << "Parent::foo()" << std::endl;
    }
};

class Child : public Parent
{
public:
    void foo()
    {
        std::cout << "Child::foo()" << std::endl;
    }
};

int main()
{
    Child obj;
    obj.callFoo();
    return 0;
}

The client code using the class is only ever using a derived object (not a base class pointer etc.). However, it's the base class version of foo() that actually gets called. The only way to resolve that is to make foo() virtual.

The second reason is simply one of correct design. If the purpose of the derived class function is to override rather than mask the original, then it should probably do so unless there is a specific reason otherwise (such as performance concerns). If you don't do that, you're inviting bugs and mistakes in future, because the class may not act as expected.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top