I have problem with subclassing and using methods.
I create an instance of class B and store it as a pointer to A. But when I use the pointer to call the overloaded method, the output is "A" not "B". Why?
This works in other languages, what am I doing wrong?
#include <iostream>
using namespace std;
class A {
public:
void f() {
cout << "A";
}
};
class B : public A {
public:
void f() {
cout << "B";
}
};
int main() {
A *a = new B();
a->f();
return 0;
}
f() needs to be declared virtual in the base class A:
class A {
public:
virtual void f() {
cout << "A";
}
};
The other languages you already worked with may default to virtual methods, but C++ doesn't (don't pay for what you don't use: virtual methods incur an indirection when calling them which means they are slightly slower than normal method calls).
By adding virtual, binding will be postponed to runtime (called dynamic binding) and which f() function call will be decided on the type of the value.
Because you have not declared function f() as virtual, binding is static (at compilation time) and will use the type of variable (but not value) to determine which f() to call. So in your present code statment a->f(); calls the A class's f() because a is pointer to the A class.
In order to achieve polymorphic behavior, the method of the base class must be virtual.
So in class A you need to change void f() to virtual void f().
The function must be declared virtual to be able to override it:
#include <iostream>
using namespace std;
class A {
public:
virtual void f() {// Here you must define the virtual.
cout << "A";
}
};
class B : public A {
public:
virtual void f() { //Here the "virtual" is optional, but a good practice
cout << "B";
}
};
int main() {
A *a = new B();
a->f();
return 0;
}
You may face this problem when having not a pointers to the base class, but the actual instances of it (not applicable to the example in this question)
In my case, I had a class Token and its subclass Word:
class Token {
public: virtual string toString() { ... }
}
class Word: public Token {
public: string toString() { ... }
}
Storing them in std::map<string, Token> and retrieving from it I expected to call Word::toString() in code like this:
std::map<string, Token> words;
words.insert("test", Word(...));
words["test"].toString();
instead I called Token::toString() every time.
Solution: to use pointers like this std::map<string, Token*> and treat all instances as pointers
(TBH, I hate pointers already)
Related
Let's consider the following code:
#include <iostream>
class Base
{
public:
void foo() //Here we have some method called foo.
{
std::cout << "Base::foo()\n";
}
};
class Derived : public Base
{
public:
void foo() //Here we override the Base::foo() with Derived::foo()
{
std::cout << "Derived::foo()\n";
}
};
int main()
{
Base *base1 = new Base;
Derived *der1 = new Derived;
base1->foo(); //Prints "Base::foo()"
der1->foo(); //Prints "Derived::foo()"
}
If I have the above stated classes, I can call the foo method from any of Base or Derived classes instances, depending on what ::foo() I need. But there is some kind of problem: what if I need the Derived class instance, but I do need to call the Base::foo() method from this instance?
The solve of this problem may be next:
I paste the next method to the class Derived
public:
void fooBase()
{
Base::foo();
}
and call Derived::fooBase() when I need Base::foo() method from Derived class instance.
The question is can I do this using using directive with something like this:
using Base::foo=fooBase; //I know this would not compile.
?
der1->Base::foo(); //Prints "Base::foo()"
You can call base class method using scope resolution to specify the function version and resolve the ambiguity which is useful when you don't want to use the default resolution.
Similar (Not exactly same case) example is mentioned # cppreference
struct B { virtual void foo(); };
struct D : B { void foo() override; };
int main()
{
D x;
B& b = x;
b.foo(); // calls D::foo (virtual dispatch)
b.B::foo(); // calls B::foo (static dispatch)
}
For example, I have three classes: A, B::A and C::A, only B and C have virtual method print(), like that:
#include <iostream>
using namespace std;
class A {
public:
virtual void print() {
return;
//do nothing
}
static void Func() {
//how to call all virtual functions print() for one class A?
print(); //doesn't work
}
};
class B : public A {
public:
virtual void print() {
cout << "B" << endl;
}
};
class C : public A {
public:
virtual void print() {
cout << "C" << endl;
}
};
int main() {
B b1;
B b2
C c;
A::Func();
return 0;
}
I wan't use print() for all inherited objects (b1, b2, c) by using just class A. How can I do it?
Declare a static class member of A that's a container of pointers to all instances of A or its subclasses. A std::list will be an excellent choice:
class A {
static std::list<A *> all_instances;
public:
// ...
};
In A's constructor, add its this to the list, saving the new list entry's iterator. In A's destructor, remove its list entry from the list.
So now you will have a private container that enumerates all instances of A, or any of its subclasses.
Writing a static class method that invokes each one's print() method becomes trivial, at this point.
Of course, a little bit of additional work is necessary to implement thread safety, if it's an issue here.
Writing the code for A's constructor or destructor will be your homework assignment.
i do not understand why this behavior occurs:
class Base
{
public:
virtual void enablePolymorphism();
};
class Derived : public Base
{
public:
void enablePolymorphism();
};
class Derived2 : public Base
{
public:
void enablePolymorphism();
};
void callMe(Base base)
{
printf("base");
}
void callMe(Derived derived)
{
printf("derived");
}
void callMe(Derived2 derived2)
{
printf("derived2");
}
int main()
{
Base* pointer = new Derived();
Base* pointer2 = new Derived2();
callMe(*pointer);
callMe(*pointer2);
return 0;
}
this is what i actually want my code to do and i want the method callMe() to be outside the classes therefore i cannot use virtual functions, i want at run-time for the program to call callMe(Derived derived) when i do callMe(*pointer) and callMe(Derived2 derived2) when i do callMe(*pointer2) for which the output would be derivedderived2 but that's not what happens, at compile-time pointer and pointer2 are assumed to be of Base class when dereferenced so the callMe(Base base) is called instead and the output is basebase. How do i achieve the output i want? thank you.
void callMe(A);
void callMe(B);
A*ptr;
callMe(*ptr); // guess which of the above is called?
this has nothing to do with polymorphism, but is simple overloading resolution.
Runtime polymorphism applies only to member functions that are marked with the virtual keyword (or that override a virtual member function):
virtual void callMe();
For a non-member function, or a non-virtual member function, the appropriate overload is selected at compile time based on the declared type (not the runtime type) of the argument(s).
The only thing the compiler sees is that the expression *pointer is of type Base& and therefore succeeds into choosing the correct overload callMe(Base) for the function.
In your case, you can use a polymorphic function instead:
#include <memory>
#include <iostream>
class Base {
public:
virtual void callMe() { std::cout << "called base"; }
};
class Derived : public Base {
public:
virtual void callMe() { std::cout << "called derived"; }
};
int main() {
std::unique_ptr<Base> pointer(new Derived());
pointer->callMe();
return 0;
}
And here is the live example.
Starting from this code:
class Base{
public:
virtual void foo(){....}
};
class Derived{
public:
void foo(){....}
};
If d is a Derived object, can I in some way invoke the foo method defined in the Base class for this object?
Edit: i mean from the outside, such that d.foo() binds to Base::foo()
Specify it explicitly in the call.
#include <iostream>
class Base{
public:
virtual void foo(){
std::cout << "Base" << std::endl;
}
};
class Derived : public Base{
public:
void foo(){
std::cout << "Derived" << std::endl;
}
};
int main()
{
Derived d;
d.Base::foo();
return 0;
}
Just qualify the call (Assuming that Derived actually inherits from Base, which in your code it doesn't):
Derived d;
d.Base::foo();
Now, while this is doable, it is also quite questionable. If the method is virtual, it is meant to be overridden and users should not call a particular override, but the final-overrider, or else they risk breaking class invariants all the way through.
Consider that the implementation of Derived::foo did some extra work needed to hold some invariant, if users call Base::foo that extra work would not be done and the invariant is broken, leaving the object in an invalid state.
To call it from outside code, you can still explicitly qualify the name in the call:
#include <iostream>
#include <vector>
struct base {
virtual void do_something() { std::cout << "Base::do_something();\n"; }
};
struct derived : public base {
virtual void do_something() { std::cout << "derived::do_something();\n"; }
};
int main() {
derived d;
d.base::do_something();
return 0;
}
If you're using a pointer to the object, you'd change that to d->base::do_something();.
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.