I guess i am having some trouble in understanding dynamic bynding.
Suppose we are having 2 classes:
class a1{ //..
virtual void print() const;
};
class a2:a1{ //...
void print() const override;
};
Why is the following true:
a2 item_son;
a1 &item_father = item_son;
item_father->print();
the print called is the one of the son.
Actually, the OP did realize the meaning of virtual overloading vs. non-virtual overloading of functions. However, I got my sample running, hence, I'd like to publish it:
#include <iostream>
class A1 {
public:
virtual void print() const
{
std::cout << "A1::print() called." << std::endl;
}
};
class A2: public A1 {
public:
void print() const override
{
std::cout << "A2::print() called." << std::endl;
}
};
class B1 {
public:
void print() const
{
std::cout << "B1::print() called." << std::endl;
}
};
class B2: public B1 {
public:
void print() const
{
std::cout << "B2::print() called." << std::endl;
}
};
using namespace std;
int main(void)
{
A2 a2;
cout << "Calling a2.print(): ";
a2.print();
A1 &a1 = a2;
cout << "Calling a1.print(): ";
a1.print();
B2 b2;
cout << "Calling b2.print(): ";
b2.print();
B1 &b1 = b2;
cout << "Calling b1.print(): ";
b1.print();
return 0;
}
Output:
Calling a2.print(): A2::print() called.
Calling a1.print(): A2::print() called.
Calling b2.print(): B2::print() called.
Calling b1.print(): B1::print() called.
Life demo on ideone
Related
I have three classes that each inherit from the other: A is inherited by B is inherited by C. I also have one virtual function in each of these classes. I want to create an A-class pointer holding a C-class object and call the B-class function like so:
class A
{
public:
virtual void doStuff() = 0;
};
class B : public A
{
public:
virtual void doStuff() override;
};
class C : public B
{
public:
void doStuff() override;
};
void B::doStuff()
{
std::cout << "Starting doStuff in B\n";
doStuff();
std::cout << "Ending doStuff in B\n";
}
void C::doStuff()
{
std::cout << "doStuff in C\n";
}
int main()
{
A *pointer = new C();
pointer->B::doStuff(); // This doesn't work
}
If I change my main slightly, I get the correct output:
int main()
{
B *pointer = new C(); // Changed A to B
pointer->B::doStuff();
}
Output
Starting doStuff in B
doStuff in C
Ending doStuff in B
How can I change my original code to use an A-class pointer and preferably only one function name?
The issue is that B::doStuff, which refers to the implementation of doStuff at class B, is not a member of A. If you are sure that the pointer is actually pointing to an instance of B or something derived from B, then you could write the following:
int main()
{
A *pointer = new C();
reinterpret_cast<B*>(pointer)->B::doStuff(); // This should work
}
If you cannot be sure about the instance type, use a dynamic_cast.
A pointer of type A can't know for certain that the B version of doStuff is accessible by default; you need to cast the pointer first.
int main()
{
A *pointer = new C();
if(B *b_ptr = dynamic_cast<B*>(pointer))
b_ptr->B::doStuff(); //Will only be executed if dynamic_cast was successful
}
Also, if you're going to use polymorphism like this, make sure you make A's destructor virtual as well, or cleanup won't behave.
class A
{
public:
virtual void doStuff() = 0;
virtual ~A() noexcept = default;
};
Here is some sample code to show why I want to do this. This code will output syntax similar to XML. Calling the "middle" class's function allows me to surround any derived class with the correct "IdentifiedRegion" tags.
#include <iostream>
#include <string>
#include <vector>
class Region
{
public:
virtual void doStuff(std::string tabs) = 0;
};
class IdentifiedRegion : public Region
{
public:
virtual void doStuff(std::string tabs) override;
};
class CircularRegion : public Region
{
public:
CircularRegion(int latitudeIn, int longitudeIn, int radiusIn) : latitude(latitudeIn), longitude(longitudeIn), radius(radiusIn) {}
void doStuff(std::string tabs) override;
private:
int latitude;
int longitude;
int radius;
};
class CountryRegion : public IdentifiedRegion
{
public:
CountryRegion(int countryCodeIn) : countryCode(countryCodeIn) {}
void doStuff(std::string tabs) override;
private:
int countryCode;
};
class StateRegion : public IdentifiedRegion
{
public:
void doStuff(std::string tabs) override;
StateRegion(std::string abbreviationIn) : abbreviation(abbreviationIn) {}
private:
std::string abbreviation;
};
void IdentifiedRegion::doStuff(std::string tabs)
{
std::cout << tabs << "<IdentifiedRegion>\n";
doStuff(tabs + "\t");
std::cout << tabs << "</IndentifiedRegion>\n";
}
void CircularRegion::doStuff(std::string tabs)
{
std::cout << tabs << "<CircularRegion>\n";
std::cout << tabs << "\t" << "<latitude>" << latitude << "</latitude>\n";
std::cout << tabs << "\t" << "<longitude>" << longitude << "</longitude>\n";
std::cout << tabs << "\t" << "<radius>" << radius << "</radius>\n";
std::cout << tabs << "</CircularRegion>\n";
}
void CountryRegion::doStuff(std::string tabs)
{
std::cout << tabs << "<CountryRegion>\n";
std::cout << tabs << "\t" << "CountryCode>" << std::to_string(countryCode) << "</CountryCode>\n";
std::cout << tabs << "</CountryRegion>\n";
}
void StateRegion::doStuff(std::string tabs)
{
std::cout << tabs << "<StateRegion>\n";
std::cout << tabs << "\t" << "<Abbreviation>" << abbreviation << "</Abbreviation>\n";
std::cout << tabs << "</StateRegion>\n";
}
int main()
{
Region *country = new CountryRegion(12);
Region *state = new StateRegion("WA");
Region *radius = new CircularRegion(10, 20, 30);
reinterpret_cast<IdentifiedRegion*>(country)->IdentifiedRegion::doStuff("");
reinterpret_cast<IdentifiedRegion*>(state)->IdentifiedRegion::doStuff("");
radius->doStuff("");
}
Consider the following example:
struct B1 {
void f() {
this->g();
std::cout << this << std::endl;
}
void g() {
std::cout << "B1::g" << std::endl;
}
};
struct B2 {
void f() {
this->g();
std::cout << this << std::endl;
}
void g() {
std::cout << "B2::g" << std::endl;
}
};
struct C: B1, B2 {
void f() {
B1::f();
B2::f();
std::cout << this << std::endl;
}
void g() {
std::cout << "C::g" << std::endl;
}
};
int main() {
C c;
c.f();
return 0;
}
For me, the output is:
B1::g
0x7fffa11436b7
B2::g
0x7fffa11436b7
0x7fffa11436b7
Let us focus on B2::f. As seen from the output, inside B2::f, this points to the beginning of the object of type C. So, how is this->g() resolved correctly to B2::g()?
No functions are virtual here. So you you call g member function from B1::f you call by definition B1::g. Things would indeed go differently if g was virtual, because then all f functions would call C::g (just try to replace void g() with virtual void g() in all 3 structs)
digging some codes, I found a curiously manner to call a method from an instance object which I will show in the example code bellow:
class Example{
public:
void Print(){ std::cout << "Hello World" << std::endl;}
};
int main(){
Example ex;
ex.Example::Print(); // Why use this notation instead of just ex.Print();
return 0;
}
There is any behaviour difference between ex.Example::Print() and the standard way ex.Print()? Why the author' code used the former instead of the latter?
Thanks in advance
The difference is that ex.Example::Print() specifies that you want the version of Print() defined in the class Example. In this particular example, there's no difference. However, consider the following:
#include <iostream>
class One {
int i;
public:
One(int ii) : i(ii) {}
virtual void print() { std::cout << i << std::endl; }
};
class Two : public One {
int j;
public:
Two(int ii, int jj) : One(ii), j(jj) {}
void print() override {
One::print();
std::cout << j << std::endl;
}
};
class Three : public Two {
int k;
public:
Three(int ii, int jj, int kk) : Two(ii, jj), k(kk) {}
void print() override {
Two::print();
std::cout << k << std::endl;
}
};
int main() {
Three four(1, 2, 3);
four.print();
std::cout << std::endl;
four.One::print();
std::cout << std::endl;
four.Two::print();
std::cout << std::endl;
four.Three::print();
std::cout << std::endl;
}
The output will be:
1
2
3
1
1
2
1
2
3
ex.Example::Print(); // Why use this notation instead of just ex.Print();
Given the posted code, that is the same as:
ex.Print();
It will make a difference only if name hiding comes into play and you want to be explicit about calling a particular version of the function.
Ex:
struct Foo
{
void Print() const { std::cout << "Came to Foo::Print()\n"; }
};
struct Bar : Foo
{
void Print() const { std::cout << "Came to Bar::Print()\n"; }
};
int main()
{
Bar b;
b.Print(); // Calls Bar::Print()
b.Foo::Print(); // Calls Foo::Print()
}
That's just the mechanics of how things work. As a design choice, it will be better to use virtual functions:
struct Foo
{
virtual void Print() const { std::cout << "Came to Foo::Print()\n"; }
};
struct Bar : Foo
{
virtual void Print() const { std::cout << "Came to Bar::Print()\n"; }
};
No difference between calling ex.Example::Print() and ex.Print() in this example.
The only use/benefit of this invocation I can think of is with inheritance; You can explicitly call over-ridden method in parent class using this syntax from an instance of derived class.
I have some doubts about the result of the following snippet. Thank you in advance!
why isn't the B1 destructor called? In my opinion, "Dest B" should display ahead of "Dest A"
Any explanation would be appreciated.
class A1 {
public:
A1() { cout << "Const A" << endl; }
~A1() { cout << "Dest A" << endl; }
virtual const char* ClassName() const{ return ("A"); }
};
class B1:public A1 {
public:
B1() { cout << "Const B" << endl; }
~B1() { cout << "Dest B" << endl; }
virtual const char* ClassName() const { return ("B"); }
};
void foo1(A1 *a1)
{
cout << "foo1 has been passed an object of class " << a1->ClassName() << endl;
delete a1;
}
int main()
{
B1 *b1 = new B1;
foo1(b1);
return 0;
}
Since your class A1 has non-virtual destructor, your delete a1 produces undefined behavior. It is illegal to apply delete to a pointer of type A1 * when the pointer actually points to a B1 object, unless class A1 has virtual destructor.
What you observe is just a specific manifestation of undefined behavior.
Declare A1's destructor as virtual and you should start observing the proper behavior.
The following test code seems to indicate that if a class has two abstract base classes with common pure virtual methods, then these methods are "shared" in the derived class.
#include <iostream>
#include <string>
using namespace std;
struct A
{
virtual string do_a() const = 0;
virtual void set_foo(int x) = 0;
virtual int get_foo() const = 0;
virtual ~A() {}
};
struct B
{
virtual string do_b() const = 0;
virtual void set_foo(int x) = 0;
virtual int get_foo() const = 0;
virtual ~B() {}
};
struct C : public A, public B
{
C() : foo(0) {}
string do_a() const { return "A"; }
string do_b() const { return "B"; }
void set_foo(int x) { foo = x; }
int get_foo() const { return foo; }
int foo;
};
int main()
{
C c;
A& a = c;
B& b = c;
c.set_foo(1);
cout << a.do_a() << a.get_foo() << endl;
cout << b.do_b() << b.get_foo() << endl;
cout << c.do_a() << c.do_b() << c.get_foo() << endl;
a.set_foo(2);
cout << a.do_a() << a.get_foo() << endl;
cout << b.do_b() << b.get_foo() << endl;
cout << c.do_a() << c.do_b() << c.get_foo() << endl;
b.set_foo(3);
cout << a.do_a() << a.get_foo() << endl;
cout << b.do_b() << b.get_foo() << endl;
cout << c.do_a() << c.do_b() << c.get_foo() << endl;
}
This code compiles cleanly in g++ 4.1.2 (admittedly old), using -std=c++98 -pedantic -Wall -Wextra -Werror. The output is:
A1
B1
AB1
A2
B2
AB2
A3
B3
AB3
This is what I desire, but I question whether this works generally, or only "by accident." Fundamentally, this is my question: can I depend on this behavior, or should I always inherit from a virtual base class for this type of scenario?
Don't make it harder than it is. A function with the same signature as a virtual function in a base class overrides the base version. Doesn't matter how many bases you have, or whether another base has a virtual function with the same signature. So, yes, this works.