I am trying to add a number of subclassed elements into a vector, iterate through them calling a overridden method and want it to call the overridden method where possible. However I have found that it appears to only be calling the superclass method.
I learnt Java and am unsure why it is doing this in C++. I have tried rewriting the code using a vector of pointers of the superclass and casting the pointer of the subclass to the superclass. Accessing this through pointers then works.
Ideally I dont want to have to put a list of pointers into the vector since then I have to manually delete each one (I believe?) to stop memory leaks since I will be creating the objects with new so they persist past the method call to add them into the vector.
Is there a better way to do this or am I stuck to using pointers and calling delete on the created objects when the parent class is unneeded? Preferably the vector would be a list of class X rather than a list of pointers of class X
My structure is:
class a { vector vec of class X,
method to create and add an instance of X into vector vec,
method to create and add an instance of Y into vector vec }
class X { talk() }
class Y : public X { talk() }
Code to demonstrate what I ideally want to do, but showing its broken by only calling the superclass method:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
class A {
public:
virtual void talk() { printf("A\n"); }
};
class B: public A {
public:
void talk() { printf("B\n"); }
};
int main(void) {
std::vector<A> vec;
std::vector<A*> vec2;
A a;
B b;
a.talk();
b.talk();
vec.push_back(a);
vec.push_back(b);
vec2.push_back(&a);
vec2.push_back(&b);
for(int i = 0; i < vec.size(); i++) {
vec[i].talk();
vec2[i]->talk(); //bad but short for example
}
}
To get the polymorphic behaviour you want you need to add the virtual specifier to the functions in the base class that you want to override in derived classes.
class A {
public:
virtual void talk() { printf("A\n"); }
};
You should also make a habit of adding the override specifier on overridden functions in derived classes so that the compiler can help you with these kind of issues.
class B: public A {
public:
virtual void talk() override { printf("B\n"); }
// ^ Compiler will report an error if base class' function
// is not virtual.
};
Also you can not assign a derived object to an instance of a base class, or slicing will occur.
std::vector<A> vec;
/* ... */
B b;
/* ... */
vec.push_back(b); // Slicing. Information only in B is lost.
Live example using virtual specifier
Live example without virtual specifier
You should declare the methods as virtual in order to be able to override them in a subclass. Also it's good practice to make the destructor virtual.
class A {
public:
virtual void talk() { printf("A\n"); }
virtual ~A(){}
};
class B: public A {
public:
// using virtual is not really necessary here, but it's good for clarity.
virtual void talk() { printf("B\n"); }
};
The method should be virtual.
In java methods are virtual by default.
class A {
public:
virtual void talk() { printf("A\n"); }
};
class B: public A {
public:
virtual void talk() override { printf("B\n"); } //override key word is in C++ 0x and above
};
I think what you are missing is the virtual keyword in your method declaration. If you want to get to a subclass method when invoking methods in a parent class, the methods have to be declared virtual.
If you don't use a pointer you will get 'object slicing' when you copy the object into the vector. This reduces the object to the base type declared in the vector template argument. So there is no subclass, so no subclass method to call, even if the method is virtual.
Related
I am currently writing a small game in OpenGL using C++. Coming from a non-C++ background, I have a simple question about overriding methods and how to call them using a pointer of a superclass type.
This is the case: I have a class Polygon containing the method void draw(). This class has two children called Rectangle and Circle, which both override the drawing method, as I am using different OpenGL calls depending on the type of polygon being drawn.
Now consider this: I wish to store all polygons (including both rectangles and circles) in an std::vector<Polygon*>. This is perfectly fine. However, iterating through the vector and calling draw automatically resorts to the superclass' version of the method.
How can I make a vector of type superclass-pointer, store pointers to subclass objects in it, and call overridden functions depending on the actual type of the object being used?
You are describing polymorphism (or a lack thereof in your current implementation).
To make your draw function polymorphic, you must declare it virtual. See below for an example:
class Polygon {
public:
virtual ~Polygon() {}
virtual void draw() = 0;
};
class Rectangle : public Polygon
{
public:
void draw() override { std::cout << "Rectangle::draw()\n"; }
};
class Circle : public Polygon
{
public:
void draw() override { std::cout << "Circle::draw()\n"; }
};
Note three extra things in the above:
I also declared the destructor virtual. This allows for proper destruction of an object through its base class pointer.
I declared the base draw method as pure-virtual (the = 0 part). This means the Polygon class is abstract and cannot itself be instantiated. You may not want that, but to me it seems there's no use for a draw method on a base class anyway. Define one if you want. Up to you.
The override specifier is optional, but recommended (language feature introduced by C++11). It instructs the compiler that you're intentionally overriding a virtual method, and so if no such method exists to be overridden then it will generate a compiler error.
You need to define the function as virtual in the base class and the override it in the subclasses. For example
#include <vector>
#include <iostream>
struct A{
virtual void p(){std::cout<<"A ";}
A(){}
virtual ~A() {};
};
struct B: public A{
void p()override{std::cout<<"B ";}
B(): A(){}
};
struct C: public A{
void p()override{std::cout<<"C ";}
C() : A(){}
};
int main()
{
A* a=new A();
B* b=new B();
C* c=new C();
std::vector<A*> v={a,b,c};
for(auto i : v)
i->p();
std::cout<<"\n";
delete a;
delete b;
delete c;
return 0;
}
prints "A B C".
Say I had 2 classes A and B, where A is a pure abstract class with a pure virtual function and B inherits from A and implements the pure virtual function. If I then have a function g() that I want to pass any instance of a subclass of A by value to (so I could mutate it without changing the original instance), how would you do that?
I know that the following code does not fit my purposes:
void g(A myObject) {} //doesn't work since A contains a pure virtual function
void g(A* myObject) {} //code compiles, but changes the original instance
Would I just copy the instance and make a pointer to it and pass into a function like above? Or is there a cleaner way to do this?
I think the best practice here is to leverage clone() method:
#include <iostream>
#include <memory>
class Base
{
public:
virtual void set_str(std::string) = 0;
virtual void print() = 0;
virtual std::unique_ptr<Base> clone() = 0;
};
class Derived: public Base
{
private:
std::string _str;
public:
std::unique_ptr<Base> clone() override {
return std::make_unique<Derived>(*this);
}
void set_str(std::string str) override {
this->_str = str;
}
void print() override {
std::cout << this->_str << std::endl;
}
};
void foo(std::unique_ptr<Base> obj) {
obj->set_str("inside");
obj->print();
}
int main() {
Derived obj;
obj.set_str("outside");
foo(obj.clone());
obj.print();
return 0;
}
What prevent the copy if indeed the pure virtual function in A. If A could be copy created from its child classes, you would have sliced the original object and only kept the fields present in A.
If you want to prevent modifications, you could:
replace the pure virtual function with a function raising an exception. Class A would become creatable while it would still break if you tried to use the function on a non subclassed object.
insert a A1 class in the hierachy with the above defined function and use it in g
This both methods create a copy of the original object and pass that (sliced) copy
You could also use a const reference:
void g(const A& myObject);
This will pass a reference to the original object, but the compiler will raise an error if you try to modify it.
I have an abstract base class which declares a pure virtual function (virtual method() = 0;). Some of the inherited classes specialize and use this method but there's one of those inherited classes in which I don't want to make this method usable. How do I do it? Is making it private the only choice?
Well, you could throw that will make tacking where it is called easier.
void method() override { throw /* whatever */ ; }
Dynamic polymorphism is a runtime property. Hence a runtime error. If you look after something that will trigger at compile time, you need static polymorphism.
template<typename Child>
struct Parent {
void callMe() {
static_cast<Child*>(this)->callMeImpl();
}
};
struct SomeChild : Parent<SomeChild> {
};
Now, if you try to call callMe form the parent that is extended by SomeChild, it will be a compile time error.
You can also hold pointer to the parent just like dynamic polymorphism, as the parent will call the child function
Is making it private the only choice?
No, that's not a choice at all since you can still access the method if it's public or protected in the base classes.
Other than implementing the method in the class and resorting to run-time failures, there's not a lot you can do. You could port the whole thing to templates and use static polymorphism which, with further trickey, you could contrive a compile-time failure in certain instances, but that could be design overkill.
I guess you could make it a normal virtual function instead of a pure virtual function like this:
virtual void method() { /* code */ }
If this function is not being used in another class, you will be able to catch that. For example you could warn yourself:
virtual void method() { error = true; } //or whatever
As others have said there is no way of enforcing this at compile time. If you are referring to a pointer to a base class there is no way the compiler can know if that pointer is referring to one of the derived classes that does implement this method or one that doesn't.
So the case will have to be handled at runtime. One option is to just throw an exception. Another option is to introduce a level of indirection so that you can ask your base class if it implements a certain function before you call it.
Say you have a Base class with three methods foo, bar and doit and some derived classes do not want to implement foo then you could split up the Base class into two base classes:
class Base1 {
public:
virtual void foo() = 0;
};
class Base2 {
public:
virtual void bar() = 0;
virtual void doit() = 0;
};
Then in places where you are currently using Base you instead use a BaseSource:
class BaseSource {
public:
virtual Base1* getBase1() = 0;
virtual Base2* getBase2() = 0;
};
where getBase1 and getBase2 can return nullptr if a BaseSource does not offer that interface:
class Derived : public BaseSource, public Base2 {
public:
// don't implement foo();
// Implemementation of Base2
void bar() override;
void doit() override;
Base1* getBase1() override { return nullptr; } // Doesn't implement Base1
Base2* getBase2() override { return this; }
};
int main() {
std::vector<std::unique_ptr<BaseSource>> objects;
objects.push_back(std::make_unique<Derived>());
for (auto& o : objects) {
auto b1 = o->getBase1();
if (b1)
b1->foo();
auto b2 = o->getBase2();
if (b2)
b2->bar();
}
}
Live demo.
In Java it's possible to write an abstract, super class with unimplemented, abstract methods and non-abstract methods which invoke the abstract methods. Then in the subclass are the abstract methods implemented. When you then make an instance of the subclass, the super class uses the implementations in the subclass. How do I accomplish this in C++?
Here is what I mean, but in Java:
SuperClass.java
public abstract class SuperClass {
public SuperClass() {
method();
}
private void method() {
unimplementedMethod();
}
protected abstract void unimplementedMethod();
}
SubClass.java
public class SubClass extends SuperClass {
public SubClass() {
super();
}
#Override
protected void unimplementedMethod() {
System.out.println("print");
}
public static void main(String[] args) {
new SubClass();
}
}
Would be awesome if you showed me how this is accomplished in C++. :)
In general, what you are looking for, is the virtual keyword. In a nutshell virtual declares the intent that this method can be overriden. Note that such a method can still have an implementation- virtual just makes it overrideable. To declare an "abstract method", you can say declare intent of please provide an implementation in the derived class with = 0, as shown below. Such methods are called pure virtual in C++.
However, there are some caveats that you should watch out for. As pointed out in a comment below, you were calling method() from within the SuperClass constructor. Unfortunately this is not possible in C++, due to the order in which objects are constructed.
In C++ a derived class constructor immediately calls it's superclass constructor before allocating its members or executing the body of the constructor. As such, the members of the base class are constructed first, and the derived class' members are constructed last. Calling a virtual method from a base class will not work as you expect in Java, since the derived class has not been constructed yet, and thus the virtual methods have not been redirected to the derived implementations yet. Hope that makes sense.
However, calling method() on a SuperClass object after creation will work as you expect: it would call the virtual function which would output "print".
class SuperClass {
public:
SuperClass() {
// cannot call virtual functions from base constructor.
}
virtual ~SuperClass() { } // destructor. as Kerrek mentions,
// classes that will be inherited from,
// should always have virtual destructors.
// This allows the destructors of derived classes
// to be called when the base is destroyed.
private:
void method() {
unimplementedMethod();
}
protected:
virtual void unimplementedMethod() = 0; // makes method pure virtual,
// to be implemented in subclass
}
SubClass.h
class SubClass : public SuperClass {
public:
SubClass() : SuperClass() { // how the superclass constructor is called.
}
// no need for "override" keyword, if the methd has the same name, it will
// automatically override that method from the superclass
protected:
void unimplementedMethod() {
std::cout << "print" << std::endl;
}
}
In C++, you should never call virtual functions in the constructor, so it doesn't work quite as literally. Best to use a separate member function
class SuperClass
{
public:
void action() { method(); } // not in the constructor, please
virtual ~SuperClass() { } // always a virtual destructor when polymorphic
protected:
void method() { unimplementedMethod(); }
private:
virtual void unimplementedMethod() = 0;
};
class SubClass : public SuperClass
{
private:
virtual void unimplementedMethod() { std::cout << "print" << std::endl; }
// no need to spell out the next couple of functions, but for your entertainment only
public:
SubClass() : SuperClass() { }
virtual ~SubClass() { }
};
Now to invoke:
int main()
{
SuperClass * p = new SubClass; // construct first...
p->action(); // ... then invoke, after construction is complete
delete p; // thank god for that virtual destructor!
}
The base constructor runs before the derived class is constructed, so you cannot call any derived functions in the base constructor, and in particular you cannot call any pure-virtual functions.
Note that you have the private and protected the wrong way round: The non-virtual accessor function should be protected so it can be used in the entire class hierarchy, but the virtual implementation function should be private, since it only needs to be seen by the accessor function in the same class. In a nutshell: protected-nonvirtual and private-virtuals.
(The usage example is a bit contrived, since you wouldn't normally use new or raw pointers in C++.)
In C++ these are called pure virtual functions/methods.
Basically you tack a "=0" at the end of a method:
virtual doSomething() = 0; // pure virtual
Search around SO for "c++ pure virtual" and you'll find tons of answers.
You need to use virtual methods. The implementation works like this:
/* here's MyBaseClass.h */
class MyBaseClass
{
public:
MyBaseClass(void);
~MyBaseClass(void);
void MyMethod();
protected:
virtual void MyUnimplementedMethod() = 0;
};
/* here's MyIneritedClass.h */
class MyInheritedClass :
public MyBaseClass
{
public:
MyInheritedClass(void);
~MyInheritedClass(void);
protected:
virtual void MyUnimplementedMethod();
};
/* here's the implementation of the method in the base class */
void MyBaseClass::MyMethod()
{
MyUnimplementedMethod();
}
/* and here's the implementation of the abstract method in the derived */
void MyInheritedClass::MyUnimplementedMethod()
{
_tprintf(L"Hello, world");
}
You declare the method as virtual:
snippet:
class Parent{
public:
virtual int methodA() {return methodB();}; // calls the abstract method
virtual int methodB() = 0; // "=0" means pure virtual, not implemented in the base
}
class Child : public Parent{
public:
virtual int methodB() { /* implementation */}
}
virtual means the child may override the implementation and the parent should be then calling the overriden implementation. Adding "=0" to the declaration of the virtual method makes it pure virtual, i.e.: the base doesn't have an implementation of its own, and relies on the implementation by the child. Such class cannot be instantiated (i.e.: abstract class).
I'm getting a pointer to a base class (which is actually a pointer to some derived class). Then I want to call a function on that derived class, but I don't know which one it is.
class Base
{
};
class DerivedOne : public Base
{
public:
void functionA()
{ int x = 0; }
};
class DerivedTwo : public Base
{
public:
void functionA()
{ int x = 0; }
};
int main()
{
Base* derivedTwoPtr = new DerivedTwo();
reinterpret_cast<DerivedOne*>(derivedTwoPtr)->functionA();
return 0;
}
This works as I want, but I have to say it looks rather dodgy. Is it defined behavior? If not, is there a legal way to dynamically resolve this?
Hey, don't do that. That's what virtual methods are for.
class Base
{
public:
virtual void functionA()=0;
};
class DerivedOne : public Base
{
public:
virtual void functionA()
{ int x = 0; }
};
class DerivedTwo : public Base
{
public:
virtual void functionA()
{ int x = 0; }
};
int main()
{
Base* derivedTwoPtr = new DerivedTwo();
derivedTwoPtr->functionA();
return 0;
}
Just use virtual functions. That's what they are intended for. Your base class should look like
class Base
{
virtual void functionA() = 0;
};
where the = 0 bit is optional. If present the virtual function is known as a pure virtual function and enforces each subclass of Base to implement the function.
Now if you call functionA through a Base pointer you will get the method appropriate to whichever subclass the pointer really points to.
is there a legal way to dynamically
resolve this?
dynamic_cast can be used to cast to a specific derived class and invoke derived class methods. But in your case the best would be to provide a virtual method in Base class and provide different implementation for the virtual method in derived classes.
You basically answered your own question here:
Casting to one class and calling
function from sibling class?
This works as I want, but I have to
say it looks rather dodgy. Is it
defined behavior? If not, is there a
legal way to dynamically resolve this?
In short:
if (DerivedOne* one=dynamic_cast<DerivedOne*>(BasePtr))
one->functionA();
else if (DerivedTwo* two=dynamic_cast<DerivedTwo*>(BasePtr))
two->functionA();
But yeah, like vava said, don't do that.