Usage of virtual keyword VS simple redefining in C++ - c++

I know that virtual functions are declared in base class and can be (don't have to be unless it's a pure virtual function) refined in a derived class. However, I don't understand the difference between redefining a virtual function and redefining a regular function. Looking at this example code:
class base {
public:
virtual int getAge(){
return 20;
}
int getId(){
return 11111;
}
};
class dri : public base{
public:
int getAge(){
return 30;
}
int getId(){
return 222222;
}
};
int main(){
dri d;
std:: cout << d.getAge() << std::endl;
std:: cout << d.getId() << std::endl;
return 0;
}
will output:
30
222222
in which case having the virtual keyword there didn't make any difference. both functions were overwritten. So why is it needed?

You didn't give an example of your class member function invocation. I guess you write the following code:
dri sth;
cout << sth.getAge() << endl;
cout << sth.getId() << endl;
However, please note that c++'s dynamic binding and polymorphism can only be applied when the instance is a pointer or reference, which actually means you should do this to get your ideal output:
base *sth = new dri();
cout << sth->getAge() << endl;
cout << sth->getId() << endl;

Related

How to make the program use function overload for derived class objects

I have classes Deck, abstract class Card and Spell and Minion which are both derived from Class. I have vector<unique_ptr<Card> > of all existing Cards and now I want to place them into Decks. I want to use void Deck::addCard(<unique_ptr<Card>) overloads for Minion and Spell.
I've tried changing the arguments and parameters to "dumb" * pointer, or just Card (which can't work, I know), references, non-references etc...
Calling addCard
Deck tmp;
for( const auto & it : mAllCards )
{
cout << typeid( *it ).name() << endl;
tmp.addCard( it );
}
addCard functions
void Deck::addCard( const unique_ptr<Card> & card )
{
cout << "basic" << endl;
}
void Deck::addCard( const unique_ptr<Minion> & minion )
{
cout << "minion" << endl;
}
void Deck::addCard( const unique_ptr<Spell> & spell )
{
cout << "spell" << endl;
}
The problem is that the Card version is called everytime, not the variants for derived types. Althrough typeid says Minion or Spell, not Card.
It doesn't work because overloads in C++ are resolved at compile time.
You should considere using a virtual print function from Card.
Something like this.
class Card {
public:
virtual void print() { std::cout << "basic" << std::endl; }
}
class Minion : public Card {
public:
void print() override { std::cout << "minion" << std::endl; }
}
class Spell : public Card {
public:
void print() override { std::cout << "spell" << std::endl; }
}
Then to use this print function you'll do this way.
void Deck::addCard(const unique_ptr<Card>& card)
{
card.print();
}
Otherwise there's always double dispatch pattern or maybe visitor pattern.
Found all this in this old post.

Declaring constructors as private shows errors. Is at least one public constructor mandatory?

I am a learner of C++. I have compiled the below program. I am working on constructors and destructors concept. I have this code here below where I declare a private destructor and access the private members using member function of the class from main(). I know that a private constructor can be declared but is a public constructor also mandatory? here is my code below:
class Book
{
private:
int *pages;
int *price;
Book() //default constructor
{
pages = new int;
price = new int;
*pages = 300;
*price = 8;
}
public:
void pre_destructor()
{
std::cout << "The pages:" << *pages << "\n";
std::cout << "The price:" << *price << "\n";
}
~Book() //destructor
{
std::cout << "The pages:" << *pages << "\n";
std::cout << "The price:" << *price << "\n";
delete pages;
delete price;
}
};
int main()
{
using namespace std;
Book book1;
cout << "Before using destructors" << endl;
cout << "---------------------------------"<< endl;
book1.pre_destructor();
cout << "After using destructors" << endl;
cout << "---------------------------------";
return 1;
}
For the above program, two errors are shown. One is in the main function where an object is declared; Error: error within content. And the second one is in the line where the constructor is called; Error:Book::Book() is private.
The main is not directly accessing the constructor in the code. Then why does it shows the access error?
No, a public constructor is not mandatory. There are use cases for private constructors.
A class with only static methods might have private (or deleted) constructors to prevent instances being created.
A singleton class (where only one instance of the class exists) might enforce its singleton status by having a private constructor. That instance can be accessed through a static getter.
You might want to follow a builder or factory pattern, where you force your users to construct instances using a process beside calling the constructor. That builder or factory would be either a member of the class or a friend, so able to call a private constructor. This scheme is much more common in Java than C++, but C++ allows it as well.
That said, you're looking to simply construct an instance of a class:
Book book1;
This use definitely requires a public default constructor.
When you make a constructor private, you need to expose a method so that external classes/methods can create object of this class. You'd do so by creating a static method, which in turn creates the object.
following code demonstrates:
#include <iostream>
class Book
{
private:
int *pages;
int *price;
Book() //default constructor
{
pages = new int();
price = new int();
*pages = 300;
*price = 8;
}
public:
static Book* constructBook()
{
return new Book();
}
void pre_destructor()
{
std::cout << "The pages:" << *pages << "\n";
std::cout << "The price:" << *price << "\n";
}
~Book() //destructor
{
delete pages;
delete price;
}
};
int main()
{
Book* book1 = Book::constructBook();
std::cout << "Before using destructors" << endl;
std::cout << "---------------------------------"<< endl;
book1->pre_destructor();
cout << "After using destructors" << endl;
cout << "---------------------------------";
delete book1;
return 0;
}
Not at all ! You don't need a public constructor but you need a factory fuction to create an instance of that class & in that case you need to qualify that function with the keyword static. See below :-
#include <iostream>
using namespace std;
class X
{
int x;
X(int x)
{
cout<<"creation\n";
this->x = x;
}
public:
static X make_X (int x) // without static error message will be : error: cannot call member function 'X X::make_X(int)' without object
{
return X(x);
}
int& getx()
{
return x;
}
~X()
{
cout<<"destruction\n";
}
};
int main()
{
auto obj = X::make_X(5);
auto ano = X::make_X(7);
cout << obj.getx() << '\t' << ano.getx() << '\n';
return 0;
}
Output is :-
creation
creation
5 7
destruction
destruction
There is no need of a public contrcutor here. But you needed make_X to create an instance of the class.
You can also use friend instead of static. In that case the code will be :-
friend X make_X (int x); // declare a prototype in the class
Then define outside the class definition :-
X make_X (int x)
{
return X(x);
}
That's how it works ! Cheers!!

Is it possible to access virtual methods of different ancestors of a polymorphic class through a single pointer?

I am building an interface, where it would be a little bit inconvenient to use separate variables to access individual interfaces, it would be great if somehow I could create a union of the two.
In a file:
struct A{
virtual int auu() { return 41; }
};
struct B{
virtual int boo() { return 43; }
};
In another file:
#include <path to A, B>
struct C : public A, public B{
int auu() { return 20; }
int boo() { return 22; }
};
And another file:
#include <declaration of A and B, but not C>
void doSth(A* a)
{
B * b = dynamic_cast<B*>(a);
/* I can only call auu with a */
a->auu();
/* I can only call boo with b */
b->boo;
/* Something like this would be ideal: */
<??? type> * C_interface = dynamic_interface_cast<B*>(a)
C_interface->auu();
C_interface->boo();
}
So is there to call both auu and boo through only one pointer variable and without the knowledge of C's implementation (not casting it to )? Also I'd like to avoid creating inheritance hierarchy that is NOT in connection with class C.
Probably the answer is no, however I'm curious if an idea like this has come up from the side of the language developers because to my primitive mind it's not a so far fetched idea.
EDIT:
In real, A and B are abstract. A is a Simulation object that has methods like size() and length(). B is an IO interface, implementing getters and setters, but it doesn't know about sizes so I have to use both interfaces in many calculations. C is a specialized Simulation that implements the former 2.
EDIT:
I rewrote the question, maybe it actually makes sense now.
I'll ilustrate the point I made in my comment. It's perfectly legal to cast between siblings, as long as the actual object is derived from both.
#include<iostream>
using namespace std;
struct A{
virtual int auu() { return 41; }
};
struct B{
virtual int boo() { return 43; }
};
struct C : public A, public B{
int auu() { return 20; }
int boo() { return 22; }
};
void take_B(B* bp)
{
cout << bp->boo() << endl; // expected
cout << "(The base class would say "
<< bp->B::boo() << ")" << endl; // base class implementation
A *ap = dynamic_cast<A*>(bp);
if(!ap)
{
cerr << "weird, this cast should be possible!" << endl;
}
else
{
cout << ap->auu() << endl; // should work
cout << "(The base class would say "
<< ap->A::auu() << ")" << endl; // base class implementation
}
}
int main()
{
C c;
take_B(&c);
cout << endl << "... and again:" << endl;
// just to clarify: The actual pointer type is irrelevant.
B *bp = &c;
take_B(bp);
return 0;
}

Casting base class to derived through std iterator in C++

in my program I have base GeneralHeader, MacHeader that derived from GeneralHeader and NetworkPacket with member Headers that is std list of GeneralHeader:
//Packet.h
enum HeaderType_t {General_Header_type, MAC_Header_type};
class GeneralHeader {
public:
bool Valid;
HeaderType_t HeaderType;
void PrintMe();
};
struct MACHeader: public GeneralHeader {
long unsigned DestAddr:48;
long unsigned SourceAddr:48;
void PrintMe();
};
struct Packet_t {
list<GeneralHeader> Headers;//TODO GeneralHeader
list<GeneralHeader>::iterator it_Header; //TODO GeneralHeader
void PrintMe();
};
While implementing the PrintMe() of Packet_t, that supposed to print all Headers according to HeaderType: if there is a GeneralHeader - it will use GeneralHeader.PrintMe() and if it is MACHeader in the list - it will print MACHeader.PrintMe())
I'm struggling to cast it_Header iterator from base GeneralHeader to derived MACHeader inside Packet_t method PrintMe():
//Packet.cpp
void GeneralHeader::PrintMe() {
std::cout << "Valid " << GeneralHeader::Valid << endl;
std::cout << "Header Type " << GeneralHeader::HeaderType << endl;
};
void HW_MACHeader::PrintMe() {
std::cout << "------------------------ " << endl;
std::cout << "---- MAC HEADER --- " << endl;
std::cout << "------------------------ " << endl;
GeneralHeader::PrintMe();
};
void NetworkPacket_t::PrintMe() {
std::cout << "Valid Packet " << NetworkPacket_t::ValidPacket << endl;
for (it_Header = Headers.begin(); it_Header != Headers.end(); it_Header++) {
switch (it_Header->HeaderType) {
case MAC_Header_type:
static_cast<HW_MACHeader*>(it_Header)->PrintMe();
break;
default:
std::cout << "default" << endl;
};
it_Header++;
};
};
The error: invalid static_cast from type 'std::_List_iterator' to type 'MACHeader*'
Thank you for any help.
The desired/normal polymorphic way would be:
Redefine PrintMe() to a virtual function so that cast is not necessary:
class GeneralHeader {
public:
bool Valid;
HeaderType_t HeaderType;
virtual void PrintMe();
};
class MACHeader: public GeneralHeader {
long unsigned DestAddr:48;
long unsigned SourceAddr:48;
public:
void PrintMe();
};
Also use vector of pointers to GeneralHeader:
list<GeneralHeader*>::iterator it_Header;
Then you can:
(*it_Header)->printMe();
The for loop will be simpler:
for (it_Header = Headers.begin(); it_Header != Headers.end();++it_Header)
(*it_Header)->PrintMe();
I don't know why you need the it_Header to be a member of the class? Can't it just be local to the loop?
You need to dereference it_Header to access the "underlying" object to address the compiler error :
static_cast<HW_MACHeader*>(*it_Header)->PrintMe();
Hoever, that will not solve your problem: you have a list of GeneralHeader; therefore because you want to downcast to an instance of HW_MACHeader, you need to use dynamic_cast; this has to be done either on a reference or a pointer:
dynamic_cast<HW_MACHeader&>(*it_Header).PrintMe();
The line above takes the object "referenced" by it_Header, and tells the compiler to cast it dynamically to a reference of type HW_MACHeader.
Note that dynamic_cast will return a null pointer if it cannot cast down to the type you want.
However, this is not a proper way to do this. You should follow user2672165's advice, and use virtual functions.

why can't access member function of base class in thus siutation?

I'm so confused, why I can't access void func(int i), anybody can help me?
Of course this is just a demo to help your understand my question easily. Its real code is huge, I want the member functions in Base and Child both available.
The output always is
**
double
2
**
struct base
{
void func(int i)
{
cout << "int" << endl;
cout << i << endl;
}
};
struct child : base
{
void func(double d)
{
cout << "double" << endl;
cout << d << endl;
}
};
child c;
c.func((int)2);
Because child::func hides base::func.
You need to either make it visible in the derived class by bringing the name in scope:
struct child : base
{
using base::func;
void func(double d)
{
cout << "double" << endl;
cout << d << endl;
}
};
or call the base version explicitly by qualifying the name at the call site:
c.base::func(2);
The implicit conversion from int to double is masking the actual problem. If you change your base class func parameter type from int to string:
struct base
{
void func(string i)
{
cout << "string" << endl;
cout << i << endl;
}
};
Then you'd receive the following error to make it clearer:
func.cpp: In function `int main()':
func.cpp:27: error: no matching function for call to `child::func(const char[13])'
func.cpp:17: note: candidates are: void child::func(double)
Where you can see it only has visibility of child::func not base::func