polymorphism with reference member variable - c++

Can someone tell me what is wrong with my program below? I am using a reference member variable in a class for polymorphism. I am expecting the second cout to say "derived2" but it says "base";
#include <iostream>
// Example program
#include <iostream>
#include <string>
class base
{
public:
virtual void print(){ std::cout<<"base"<<std::endl;}
};
class derived: public base
{
public:
virtual void print(){ std::cout<<"derived"<<std::endl;}
};
class derived2: public base
{
virtual void print(){ std::cout<<"derived2"<<std::endl;}
};
class foo
{
public:
base & bar;
base boo;
derived foobar;
derived2 foobar2;
foo(): bar(boo){}
void newfoo(base & newfoo){ bar = newfoo; bar.print();}
};
int main()
{
foo test;
test.bar.print();
test.newfoo(test.foobar2);
}
Output:
base
base

As mentioned by others, you cannot reassign a reference.
Whenever you do something like bar = newfoo you are not resetting the reference. Instead you are invoking operator= for bar with newfoo as an argument.
Therefore, in your case you are slicing your objects and (let me say) copying its base part in bar.
A kind of reference-like tool to which you can reassign exists in the standard template library and it's called std::reference_wrapper.
It follows an example based on your code that uses it and has the expected behavior:
#include<functional>
#include <iostream>
#include <string>
class base
{
public:
virtual void print() { std::cout<<"base"<<std::endl;}
};
class derived: public base
{
public:
virtual void print(){ std::cout<<"derived"<<std::endl;}
};
class derived2: public base
{
virtual void print(){ std::cout<<"derived2"<<std::endl;}
};
class foo
{
public:
std::reference_wrapper<base> bar;
base boo;
derived foobar;
derived2 foobar2;
foo(): bar(boo){}
void newfoo(base & newfoo){ bar = newfoo; bar.get().print();}
};
int main()
{
foo test;
test.bar.get().print();
test.newfoo(test.foobar2);
}
In this case, operator= actually rebinds the reference to the given object. Anyway, as you can see, in this case you must invoke get to access the underlying reference.
Note: set aside the example above, your code isn't the typical use case for a std::reference_wrapper.
I mentioned it only for the sake of completeness.

You can't 'reassign' the reference. When assignment operator is used with the reference, it assigns the underlying value.
Thus, bar = newfoo; simply assigns foo of the base type to foobar, slicing it in the process.
You could have a different behavior if you'd substitute references with pointers, which can be re-assigned.

bar is a reference to boo, and boo is of type base whatever you assign to it.
Assignment can only change a variables value, not its type.

Polymorphism does not work with references. Try this:
#include <iostream>
// Example program
#include <iostream>
#include <string>
class base
{
public:
virtual void print(){ std::cout << "base" << std::endl; }
};
class derived : public base
{
public:
virtual void print(){ std::cout << "derived" << std::endl; }
};
class derived2 : public base
{
virtual void print(){ std::cout << "derived2" << std::endl; }
};
class foo
{
public:
base* bar;
foo(): bar(0) {}
void newfoo(base* newfoo){ bar = newfoo; bar->print(); }
};
int main() {
foo test;
test.newfoo(new derived2);
}

Related

Copy Constructors of classes instantiating derived classes

I have unsuccessfully been trying to create a copy constructor of a class that instantiates a derived class.
Let's say I have the following pure virtual class:
class AbstractBar{
public:
virtual void printMe() = 0;
};
Class Bar inherits from AbstractBar as follows:
class Bar: public AbstractBar {
std::string name_;
public:
explicit Bar(std::string name) : name_ {std::move(name)}{};
void printMe() override { std::cout << name_ << std::endl; }
};
My class Foo now attempts to make use of polymorphism by declaring a pointer to type AbstractClass as follows:
class Foo{
std::unique_ptr<AbstractBar> theBar_;
public:
explicit Foo(std::unique_ptr<Bar> bar){
theBar_ = std::move(bar);
};
void printBar(){
theBar_->printMe();
}
};
I do however want Foo to be copied so I add the following copy constructor:
Foo(const Foo &other) {
theBar_ = std::unique_ptr<AbstractBar>();
*theBar_ = *(other.theBar_);
}
And this is where it breaks.
What I gather is that this may be a problem since theBar in the copy constructor thinks it is pointing to an AbstractBar but when I try to copy the object it points to, in the next line, I actually give it a derived Bar class.
Is there a proper way to implement this copy constructor?
First off, std::unique_ptr<T> is indeed unique. Therefore you cannot expect two things to point to the same instance-of-whatever by copying them. That said, I think what you're trying to do is clone whatever the "thing" is that is held by that member unique_ptr to allow a deep copy of a Foo.
If that is the case, you need a covariant clone. See below:
#include <iostream>
#include <string>
#include <memory>
struct AbstractBar
{
virtual ~AbstractBar() = default;
virtual std::unique_ptr<AbstractBar> clone() = 0;
virtual void printMe() = 0;
};
class Bar : public AbstractBar
{
std::string name_;
public:
explicit Bar(std::string name) : name_{std::move(name)} {};
std::unique_ptr<AbstractBar> clone() override
{
return std::make_unique<Bar>(name_);
}
void printMe() override
{
std::cout << name_ << std::endl;
}
};
class Foo
{
std::unique_ptr<AbstractBar> theBar_;
public:
explicit Foo(std::unique_ptr<Bar> bar)
: theBar_(std::move(bar))
{
}
Foo(const Foo &other)
: theBar_(other.theBar_->clone())
{
}
void printBar()
{
theBar_->printMe();
}
};
int main()
{
Foo foo(std::make_unique<Bar>("Some String"));
Foo bar(foo);
foo.printBar();
bar.printBar();
}
Important: foo and bar will each have their own Bar instance via a unique pointer to the abstract base of Bar, namely AbstractBar. Hopefully that was the intent. This isn't the only way to do this, but it is probably the easiest to understand.

Access another Base Classes member from Abstract Base Class

I wonder if it is possible to declare a pure virtual function in class AbstractBase and make a Base classes member visible in Derived so it will use the member of Base and not look for a implementation in Derived. So far, i tried making Base's member visual by trying to use using but it won't compile since the look up, in this case, seems to ignore using. Is this possible at all? Here is my code:
#include <iostream>
using namespace std;
class AbstractBase {
public:
AbstractBase(){}
virtual ~AbstractBase(){}
protected:
virtual void f() = 0;
};
class Base {
public:
Base(){}
protected:
void f() {cout << "called Base's f()" << endl;}
};
class Derived : public Base, public AbstractBase {
public:
Derived(){}
//using Base::f; /*this won't compile*/
private:
void f(){} /*Access Base's f() here rather than implement*/
};
int main()
{
Derived d;
}
Use :: operator:
class Derived : public Base {
public:
Derived(){}
private:
void f(){ Base::f() }
};
Also, you don't need to inherit from AbstractBase.
It looks to me that you would like f() to be pure-virtual but provide default implementation. In this case, it can be achieved this way:
#include <iostream>
using namespace std;
struct AbstractBaseWithDefaultF
{
virtual ~AbstractBaseWithDefaultF() = default;
virtual void f() = 0;
};
void AbstractBaseWithDefaultF::f()
{
cout << "called AbstractBaseWithDefaultF's f()" << endl;
}
struct Derived : AbstractBaseWithDefaultF
{
void f() override
{
AbstractBaseWithDefaultF::f();
cout << "called Derived's f()" << endl;
}
};
int main()
{
Derived d;
d.f();
}
Output:
called AbstractBaseWithDefaultF's f()
called Derived's f()
Here's a live Wandbox example.

Base class method alias

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)
}

Call base class method from derived class object

How can I call a base class method which is overridden by the derived class, from a derived class object?
class Base{
public:
void foo(){cout<<"base";}
};
class Derived:public Base{
public:
void foo(){cout<<"derived";}
}
int main(){
Derived bar;
//call Base::foo() from bar here?
return 0;
}
You can always(*) refer to a base class's function by using a qualified-id:
#include <iostream>
class Base{
public:
void foo(){std::cout<<"base";}
};
class Derived : public Base
{
public:
void foo(){std::cout<<"derived";}
};
int main()
{
Derived bar;
//call Base::foo() from bar here?
bar.Base::foo(); // using a qualified-id
return 0;
}
[Also fixed some typos of the OP.]
(*) Access restrictions still apply, and base classes can be ambiguous.
If Base::foo is not virtual, then Derived::foo does not override Base::foo. Rather, Derived::foo hides Base::foo. The difference can be seen in the following example:
struct Base {
void foo() { std::cout << "Base::foo\n"; }
virtual void bar() { std::cout << "Base::bar\n"; }
};
struct Derived : Base {
void foo() { std::cout << "Derived::foo\n"; }
virtual void bar() { std::cout << "Derived::bar\n"; }
};
int main() {
Derived d;
Base* b = &d;
b->foo(); // calls Base::foo
b->bar(); // calls Derived::bar
}
(Derived::bar is implicitly virtual even if you don't use the virtual keyword, as long as it's signature is compatible to Base::bar.)
A qualified-id is either of the form X :: Y or just :: Y. The part before the :: specifies where we want to look up the identifier Y. In the first form, we look up X, then we look up Y from within X's context. In the second form, we look up Y in the global namespace.
An unqualified-id does not contain a ::, and therefore does not (itself) specify a context where to look up the name.
In an expression b->foo, both b and foo are unqualified-ids. b is looked up in the current context (which in the example above is the main function). We find the local variable Base* b. Because b->foo has the form of a class member access, we look up foo from the context of the type of b (or rather *b). So we look up foo from the context of Base. We will find the member function void foo() declared inside Base, which I'll refer to as Base::foo.
For foo, we're done now, and call Base::foo.
For b->bar, we first find Base::bar, but it is declared virtual. Because it is virtual, we perform a virtual dispatch. This will call the final function overrider in the class hierarchy of the type of the object b points to. Because b points to an object of type Derived, the final overrider is Derived::bar.
When looking up the name foo from Derived's context, we will find Derived::foo. This is why Derived::foo is said to hide Base::foo. Expressions such as d.foo() or, inside a member function of Derived, using simply foo() or this->foo(), will look up from the context of Derived.
When using a qualified-id, we explicitly state the context of where to look up a name. The expression Base::foo states that we want to look up the name foo from the context of Base (it can find functions that Base inherited, for example). Additionally, it disables virtual dispatch.
Therefore, d.Base::foo() will find Base::foo and call it; d.Base::bar() will find Base::bar and call it.
Fun fact: Pure virtual functions can have an implementation. They cannot be called via virtual dispatch, because they need to be overridden. However, you can still call their implementation (if they have one) by using a qualified-id.
#include <iostream>
struct Base {
virtual void foo() = 0;
};
void Base::foo() { std::cout << "look ma, I'm pure virtual!\n"; }
struct Derived : Base {
virtual void foo() { std::cout << "Derived::foo\n"; }
};
int main() {
Derived d;
d.foo(); // calls Derived::foo
d.Base::foo(); // calls Base::foo
}
Note that access-specifiers both of class members and base classes have an influence on whether or not you can use a qualified-id to call a base class's function on an object of a derived type.
For example:
#include <iostream>
struct Base {
public:
void public_fun() { std::cout << "Base::public_fun\n"; }
private:
void private_fun() { std::cout << "Base::private_fun\n"; }
};
struct Public_derived : public Base {
public:
void public_fun() { std::cout << "Public_derived::public_fun\n"; }
void private_fun() { std::cout << "Public_derived::private_fun\n"; }
};
struct Private_derived : private Base {
public:
void public_fun() { std::cout << "Private_derived::public_fun\n"; }
void private_fun() { std::cout << "Private_derived::private_fun\n"; }
};
int main() {
Public_derived p;
p.public_fun(); // allowed, calls Public_derived::public_fun
p.private_fun(); // allowed, calls Public_derived::public_fun
p.Base::public_fun(); // allowed, calls Base::public_fun
p.Base::private_fun(); // NOT allowed, tries to name Base::public_fun
Private_derived r;
r.Base::public_fun(); // NOT allowed, tries to call Base::public_fun
r.Base::private_fun(); // NOT allowed, tries to name Base::private_fun
}
Accessibility is orthogonal to name lookup. So name hiding does not have an influence on it (you can leave out public_fun and private_fun in the derived classes and get the same behaviour and errors for the qualified-id calls).
The error in p.Base::private_fun() is different from the error in r.Base::public_fun() by the way: The first one already fails to refer to the name Base::private_fun (because it's a private name). The second one fails to convert r from Private_derived& to Base& for the this-pointer (essentially). This is why the second one works from within Private_derived or a friend of Private_derived.
First of all Derived should inherit from Base.
class Derived : public Base{
That said
First of you can just not have foo in Derived
class Base{
public:
void foo(){cout<<"base";}
};
class Derived : public Base{
}
int main(){
Derived bar;
bar.foo() // calls Base::foo()
return 0;
}
Second you can make Derived::foo call Base::foo.
class Base{
public:
void foo(){cout<<"base";}
};
class Derived : public Base{
public:
void foo(){ Base::foo(); }
^^^^^^^^^^
}
int main(){
Derived bar;
bar.foo() // calls Base::foo()
return 0;
}
Third you can use qualified id of Base::foo
int main(){
Derived bar;
bar.Base::foo(); // calls Base::foo()
return 0;
}
Consider making foo() virtual in the first place.
class Base {
public:
virtual ~Base() = default;
virtual void foo() { … }
};
class Derived : public Base {
public:
virtual void foo() override { … }
};
However, this does the job:
int main() {
Derived bar;
bar.Base::foo();
return 0;
}
An important [additional] note: you will still have compilation errors if Name Hiding occurs.
In this case, either utilize the using keyword, or use the qualifer. Additionally, see this answer as well.
#include <iostream>
class Base{
public:
void foo(bool bOne, bool bTwo){std::cout<<"base"<<bOne<<bTwo;}
};
class Derived : public Base
{
public:
void foo(bool bOne){std::cout<<"derived"<<bOne;}
};
int main()
{
Derived bar;
//bar.foo(true,true); // error: derived func attempted
bar.foo(true); // no error: derived func
bar.Base::foo(true,true); // no error: base func, qualified
return 0;
}

Use the base-class virtual method

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();.