override c++ virtual method
Asked Answered
C

3

12

I have a class template where some methods are defined as virtual to give the ability for the user of my class to give an implementation for them in his derived class. Note that in my template class there is some non-virtual methods that makes use of the virtual one (a virtual class that should return a value is called in a non-virtual class).

Can you give me a simple example of a correct code where the virtual method of the parent class should return a value (but it's implementation is provided in a child class) and the value returned by the virtual method in the parent class is used in other methods of that class. Because I saw somewhere (for example here: Safely override C++ virtual functions) that this can cause some problems and the user defined method will note override the virtual method of the parent class.

Note: I program with Code::Blocks using g++ compiler.

EDIT: as requested here a simple example of what I want:

template<typename T>
class parent {
public:
  // Public methods that user can call
  int getSomething(T t);
  void putSomething(T t, int x);

  // public method that user should implement in his code
  virtual float compute(T t) { }

  // protected or private methods and attributes used internally by putSomething ...
  float doComplexeThings(...); // this can call
};

The method compute() should be implemented by the user (the child class). However, this method compute() is called by putSomething() and doComplexeThings() for example.

Cusack answered 26/1, 2012 at 12:26 Comment(4)
For what you describe, a virtual method may not be needed (static polymorphism may work for you) - hard to tell by your description. Please post sample code that you have written so we have a better sense of exactly what you are trying to do.Potful
The example in the linked question was about what you think is an override but actually declares an overload because of an error, e.g. a const missing and was not about return values. What do you think is the danger, exactly?Cannon
In classic template code, you do not even need to declare a virtual float compute(T t). You simply use it (call it) inside putSomething() and doComplexeThings() via t.compute(), if you have a handle to the instance. The compiler will error if your class T does not implement compute. In this way, parent and T actually do not even have to live in the same inheritance hierarchy: ie, T is a child of parent relationship is not required. Doing so also can give you a chance to give parent a more meaningful name (since the is-a relationship is not necessary).Potful
@Potful I don't understand why you are talking about a relationship between T and parent. T is not necessarily a class, it's just a type that the class template (parent) use because I want to make it independent of the type of manipulated data. Forget about T, my problem is just: where and how to define the method float compute(...) which is called by doComplexeThings(...) and putSomething(...) , while the code of the method float compute(...) should be given by the user.Cusack
T
21

You just have to make sure that the methods have the same signature (including const/mutable modifiers and argument types). You can use a pure virtual definition to provoke compiler errors if you fail to override the function in a subclass.

class parent {
public:
  // pure virtual method must be provided in subclass
  virtual void handle_event(int something) = 0; 
};

class child : public parent {
public:
  virtual void handle_event(int something) {
    // new exciting code
  }
};

class incomplete_child : public parent {
public:
  virtual void handle_event(int something) const {
    // does not override the pure virtual method
  }
};

int main() {
  parent *p = new child();
  p->handle_event(1); // will call child::handle_event
  parent *p = new incomplete_child(); // will not compile because handle_event
                                      // was not correctly overridden
}
Theism answered 26/1, 2012 at 12:33 Comment(3)
Covariant return types are allowed for virtual methods.Winslow
@als, just a small detail to 'covariant return types are allowed', covariant types are only allowed if the function returns a reference or pointer. I know that you know this, but I am leaving this comment for others.Spates
@Theism The problem with your answer is that you are forcing a change in the semantics just to avoid a potential problem. In the original case the function was present but could be overloaded, in your proposed solution it must be overloaded. This does not tackle errors while overloading an existing function, but rather forces derived classes to overload.Spates
S
22

If you can use C++11 features in your compiler then overrides can be tagged as so with the override special identifier:

 float compute() override;

The above line in a derived class will cause a compiler error as the function does not override a member function in the base (incorrect signature, missing argument). But note that this must be done in each derived class, it is not a solution that you can impose from the base class.

From the base class you can only force the override by making the function pure virtual, but that changes the semantics. It does not avoid problems while overriding, but rather forces overriding in all cases. I would avoid this approach, and if you are to follow it and there is a sensible implementation for the base type, make the function virtual and provide a definition so that your derived classes's implementation can just call the functions the base type (i.e. you force the implementation, but in the simplest cases it will just forward the call to the parent)

Shipman answered 26/1, 2012 at 13:28 Comment(1)
+1 for an interesting C++11 feature - helpful for ensuring that your method really is overriding somethingPotful
T
21

You just have to make sure that the methods have the same signature (including const/mutable modifiers and argument types). You can use a pure virtual definition to provoke compiler errors if you fail to override the function in a subclass.

class parent {
public:
  // pure virtual method must be provided in subclass
  virtual void handle_event(int something) = 0; 
};

class child : public parent {
public:
  virtual void handle_event(int something) {
    // new exciting code
  }
};

class incomplete_child : public parent {
public:
  virtual void handle_event(int something) const {
    // does not override the pure virtual method
  }
};

int main() {
  parent *p = new child();
  p->handle_event(1); // will call child::handle_event
  parent *p = new incomplete_child(); // will not compile because handle_event
                                      // was not correctly overridden
}
Theism answered 26/1, 2012 at 12:33 Comment(3)
Covariant return types are allowed for virtual methods.Winslow
@als, just a small detail to 'covariant return types are allowed', covariant types are only allowed if the function returns a reference or pointer. I know that you know this, but I am leaving this comment for others.Spates
@Theism The problem with your answer is that you are forcing a change in the semantics just to avoid a potential problem. In the original case the function was present but could be overloaded, in your proposed solution it must be overloaded. This does not tackle errors while overloading an existing function, but rather forces derived classes to overload.Spates
H
0

This question is asked in 2013. It's pretty old but I found something new which doesn't exist in the answers.

We need to understanding three concept is overload, overwrite, and hide.

Short answer, you want to overload the inheritance function from base class. However, overload is the mechanism to add multiple behavior for function which needs all these functions under the same scale. But the virtual function is in the Base class obviously.

class A {
public:
  virtual void print() {
    cout << id_ << std::endl;
  }
private:
  string id_ = "A";
};

class B : A {
public:
  using A::print;
  void print(string id) {
    std::cout << id << std::endl;
  }
};

int main(int argc, char const *argv[]) {
  /* code */
  A a;
  a.print();
  B b;
  b.print();
  b.print("B");
  return 0;
}

Add using A::print; in your derive class will do the work!

Though I don't feel it's a good idea since the philosophy behind the overload and inheritance is different, it may not a good idea to nest them together.

Holophrastic answered 21/2, 2018 at 16:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.