I am in the process of creating a scene graph for a 2D game engine. I've created a base class called Node, which is derived by Sprite, which in turn is derived by Player. Each class has the virtual function update(). I want to call every update() in each class. I don't know if this is possible (Except using base::update(), but that's a little messy with many derived classes).
The following code provides a little insight into the current structure of my project.
#include <iostream>
class Base
{
public:
virtual void print()
{
std::cout << "Hello from Base ";
}
};
class Derived : public Base
{
public:
virtual void print()
{
std::cout << "and Derived!" << std::endl;
}
};
int main()
{
Derived foo = Derived();
foo.print(); // Obviously outputs only "and Derived!"
}
While the above does exactly as expected, my desired output is actually "Hello from Base and Derived!".
I know I can put Base::print() at the top of Derived::print(), but I am looking for a method to that's a little cleaner with many derived classes on top of each other.
I'm a little new to C++ as a language, and I couldn't find info on this subject. I'm open to complete changing my approach if it's not in the style of proper polymorphism. I'd rather do things right than botching it to just get this affect.
I know I can put Base::print() at the top of Derived::print(), but I am looking for a method to that's a little cleaner with many derived classes on top of each other.
You have to do that explicitely if you want it, That's the whole point of overriding with polymorphism.
class Derived : public Base
{
public:
virtual void print()
{
Base::print();
std::cout << "and Derived!" << std::endl;
}
};
As you're mentioning graphs (tree like structures), you should have a look at the Visitor Pattern.
Sometimes C++ does something you are not expecting.
My advice is to use a feature of the C language that it has to support.
In this case, I used union to achieve the programmatic effect you are seeking:
#include <iostream>
class Base
{
public:
virtual void print()
{
std::cout << "Hello from Base ";
}
};
class Derived : public Base
{
public:
virtual void print()
{
std::cout << "and Derived!" << std::endl;
}
};
int main(void);
int main()
{
Base foo;
Derived bar;
union foobar {Base *b; Derived *d;} fb;
fb.b = &foo; fb.b->print();
fb.d = &bar; fb.d->print();
return 0;
}
CODE LINK: http://ideone.com/JdU8T6
Related
I am exploring diamond problem. I have written below code. However it shows ambiguous issue. How to resolve it?
Is it possible without overriding method in Snake class?
#include <iostream>
class LivingThing {
protected:
void breathe()
{
std::cout << "I'm breathing as a living thing." << std::endl;
}
};
class Animal : virtual protected LivingThing {
protected:
void breathe() {
std::cout << "I'm breathing as a Animal." << std::endl;
}
};
class Reptile : virtual public LivingThing {
public:
void breathe() {
std::cout << "I'm breathing as a Reptile." << std::endl;
}
};
class Snake : public Animal, public Reptile {
};
int main() {
Snake snake;
snake.breathe();
getchar();
return 0;
}
What happens here is that Animal and Reptile both overwrite the LivingThing::breathe() method with their own version. Snake, thus, inherits two different methods, both called breathe, one from each of its base classes. When you then write
snake.breathe();
the name breathe is ambiguous because it could refer to either Animal::breathe or Reptile::breathe. You have to explicitly tell which one should be called, for example
snake.Reptile::breathe();
This is most likely not what you wanted. breathe() is not a virtual method. You most likely wanted it to be a virtual method, however, in which case you most definitely should have a look at How does virtual inheritance solve the "diamond" (multiple inheritance) ambiguity?.
Here is my code:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void Sub1() = 0;
virtual void Sub2();
virtual void Sub3();
void Sub4();
};
class A : public Base
{
public:
void Sub2();
void Sub4();
};
class B : public A
{
public:
virtual void Sub1();
void Sub2();
};
class C : public Base
{
public:
virtual void Sub1();
virtual void Sub4();
};
void Base::Sub2()
{
cout << "Hello from Base::Sub2()" << endl;
}
void Base::Sub3()
{
cout << "Hello from Base::Sub3()" << endl;
Sub1(); // DONT MISS THIS CALL IN YOUR ANSWER
}
void Base::Sub4()
{
cout << "Hello from Base::Sub4()" << endl;
}
void A::Sub2()
{
cout << "Hello from A:Sub2()" << endl;
}
void A::Sub4()
{
cout << "Hello from A:Sub4()" << endl;
}
void B::Sub1()
{
cout << "Hello from B:Sub1()" << endl;
}
void B::Sub2()
{
cout << "Hello from B:Sub2()" << endl;
}
void C::Sub1()
{
cout << "Hello from C:Sub1()" << endl;
}
void C::Sub4()
{
cout << "Hello from C:Sub4()" << endl; //error used to say from Sub2
}
void Sub(Base& x)
{
x.Sub1();
x.Sub2();
x.Sub3();
}
void AnotherSub(A& a)
{
a.Sub1();
a.Sub2();
a.Sub4();
}
int main()
{
A a; // wont compile
B b;
C c;
Sub(a);
Sub(b);
Sub(c);
AnotherSub(b);
}
I'm having trouble with the A a; and obviously the end Sub(a); because a cannot be used, but at the very end, where it says, "error: cannot declare variable ‘a’ to be of abstract type ‘A’" Any help would be appreciated, Thanks.
--- Also if it helps, the output without the A a; works and looks like:
Hello from B:Sub1()
Hello from B:Sub2()
Hello from Base::Sub3()
Hello from B:Sub1()
Hello from C:Sub1()
Hello from Base::Sub2()
Hello from Base::Sub3()
Hello from C:Sub1()
Hello from B:Sub1()
Hello from B:Sub2()
Hello from A:Sub4()
This line into your class Base:
virtual void Sub1() = 0;
Make the class Base or any class extending it an abstract class if you don't implement the function Sub1, which is the case of your class A.
You cannot create instances of abstract classes, as it has methods with no implementation, which means impossible to call. This kind of classes can only be used through inheritance.
So you need to implement it directly on Base or A if you want to create A instances.
Your compiler is right: you cannot create a variable of abstract typ. Your class Base is abstract because it declares a pure virtual method, that is a function without any implementation:
virtual void Sub1() = 0;
Your class A derived from Base is abstract, too, because it does not provide an overriding implementation for the method.
You must provide an implementation to all declared virtual methods to make a type instantiable. As you override a pure virtual Sub1() in class B, you can create variables of class B (and its descendant classes), but class A cannot be used itself as an actual type for a variable.
You are extending Base class from A but you didn't implement the pure virtual method in A. So, you need to make A as abstract class. It can't be a concrete class.
To ignore making A as abstract and to use it as a concrete class, just override the pure virtual method too and define it with no statements in it. Now you can create an instance for A.
What I want to add is Since Base is abstract and class A doesn't implement one of its pure virtual function so A is also abstract. As abstract class cant be instantiated (only pointers and references are allowed) we use pointers of abstract class (say pointer to A) to instantiate object of classes derived from abstract class (A or base in this case).
So you need to provide implementation of pure virtual function and have to use pointer to A like
A *a;
a = new B(); // it would compile now
Hope you got my point.
If I have a Base and a Derived Class:
class Base {
//...
};
class Derived : public Base {
//...
};
Is it possible to overload functions in the following way?
void DoSomething(Base b) {
cout << "Do Something to Base" << endl;
}
void DoSomething(Derived d) {
cout << "Do Something to Derived" << endl;
}
What happens if I do this:
int main() {
Derived d = Derived();
DoSomething(d);
}
Derived is also a Base.. so which version gets called?
Yes, C++ lets you overload functions for base and derived classes. In fact, this mechanism is used by the standard library <algorithm> functions to select the correct algorithm depending on the types of the iterators passed in.
A Derived object is also a Base, but DoSomething(Derived) is an exact match, so it's preferred. DoSomething(d) will call DoSomething(Derived).
However, note that you can't get polymorphic behaviour this way. That is, if you have a Base& that actually refers to a Derived object, it still calls DoSomething(Base): that is, it dispatches on the static type. (In fact, since you are passing by value, it copies out only the Base part of the object into the parameter.) To get polymorphic behaviour, you would have to make DoSomething into a virtual member function (or make DoSomething(Base& b) call a virtual member function on b.)
The derived function will be called and used because it matches this "DoSomething(Derived d)"
signature.
Have you consider using the code like this instead:
#include<iostream>
using namespace std;
class Base {
public:
virtual void DoSomething();
};
class Derived : public Base {
public:
void DoSomething() override;
};
void Base:: DoSomething() {
cout << "Do Something to Base" << endl;
}
void Derived :: DoSomething() {
cout << "Do Something to Derived" << endl;
}
int main() {
Base *d = new Derived();
d->DoSomething();
delete d;
return 0;
}
It accomplished the same task, and allows you to take advantage of polymorphisms strength.
I'm attempting to call a method from a base class with the same name as a method in the derived class. Here's a simplified example:
#include <iostream>
using namespace std;
class Base
{
public:
void print() {
cout << "Printing from base" << endl;
}
void print(int num) {
cout << "Printing number from base: " << num << endl;
}
};
class Derived : public Base
{
using Base::print;
public:
void print() {
cout << "Printing from derived" << endl;
}
};
int main()
{
Derived x;
x.print();
x.Base::print(1);
//x.print(1); // Gives a compilation error
return 0;
}
Basically, I'd like to be able to call x.print(1) and get "Printing number from base: 1", that is, automatically call the method which matches the signature, even though it resides in the base class.
Without the using Base::print;, I get error: no matching function for call to 'Derived::print(int)', which makes perfect sense due to name hiding.
Thus, I added that line, but now the error is error: 'void Base::print(int)' is inaccessible
Why is this the case? I use public inheritance, so I would have thought it was readily available?
As demonstrated in the example, it works fine to manually call x.Base::print(1);, but I would like to do it more transparently. Then of course I can re-implement a wrapper to the function in the derived class, but that does not seem very elegant either.
I apologize if this has been covered in an earlier question, I read a bunch of them and found a lot of similar cases, but nothing that helped me.
The placement of the using directive decides about the visibility. Simply place it into the public area and you should be fine:
//...
class Derived : public Base
{
public:
using Base::print;
void print() {
cout << "Printing from base" << endl;
}
};
//...
http://ideone.com/06NNk
You can make your functions virtual. Any virtual functions inherited from the base class that aren't overloaded will be called through the derived class.
class base
{
public:
virtual void Foo() {}
}
class Derived
{
}
Derived d;
d.foo(); // calls base::foo()
Sample code
#include <iostream>
using namespace std;
class Base
{
public:
virtual void Func()
{
cout << "\nIn base func";
}
};
class Derived : public Base
{
public:
void Func()
{
cout << "\nIn derived";
}
};
class Derived2 : public Derived
{
public:
void Func()
{
cout << "\nIn derived2";
}
};
int main()
{
Base* lnewbase = new Derived2();
lnewbase->Func();
return 0;
}
As an example, in the above code, I do not want Func() of Derived to be inherited (seal in C#) which is why there is no virtual keyword although I am aware that it does not change anything in this case. Is there any way to disallow that function to be inherited while making sure it remains a public method?
No; C++ has no equivalent to C#'s sealed modifier.
There is nothing you can do.
Once you make a function in a base class virtual, there's nothing that can be done to get rid of that aspect of it. I can only think of a few things to almost get around it:
Don't make it virtual;
Make a new, public, non-virtual function in Derived that does what you need.
However, in either case, Derived2 will still be able to make its own version of Func(), which will give you the same problem.