C++ class casting - class

Guys I am trying to create an object that can instantiate the other types that inherit it:
#include <iostream>
#include <cstdlib>
class Animal {
public:
char *nome;
Animal (char *nome) {
this->nome = nome;
}
};
class Cachorro : public Animal {
public:
bool enterraOsso;
Cachorro (char* nome, bool enterraOsso) : Animal(nome) {
this->enterraOsso = enterraOsso;
}
};
class Passaro : public Animal {
public:
bool voar;
Passaro (char* nome, bool voar) : Animal(nome) {
this->voar = voar;
}
};
int main() {
Animal *animal;
animal = new Cachorro("Scooby", true);
std::cout << animal->nome << ", " << animal->enterraOsso << std::endl;
animal = new Passaro("Piopio", false);
std::cout << animal->nome << ", " << animal->voar << std::endl;
return 0;
}
The idea is to access the subclass attributes from the superclass also.
I don't know if this is a cast or polymorphism, in Java I know it is possible, but can't do it in C++.
Thank you for all your help.

You can, it is bad design though for a Base class to know about its children:
int main() {
Animal *animal;
animal = new Cachorro("Scooby", true);
Cachorro * c = reinterpret_cast<Cachorro*>(animal);
std::cout << animal->nome << ", " << c->enterraOsso << std::endl;
animal = new Passaro("Piopio", false);
Passaro * p = reinterpret_cast<Passaro*>(animal);
std::cout << animal->nome << ", " << p->voar << std::endl;
}

Related

Segmentation Error: Help on the correct allocation memory when saving & loading binary files containing a specific structure from a class

This is my first time asking a question, so apologies if it is not done 100%:
I have a class which saves and loads a binary file with a specific data structure.
If the program creates an instance of the class, save the binary file, and creates another instance of the class to load/read the binary file consequently, everything seems 100% correct.
However, if I run the program to save the binary file and then run it again to load/read that binary file, it gives me a segmentation fault at the end.
The program still does everything it needs to do before the segmentation fault, except deconstructing the class at the end (obviously).
It looks like my allocation of the memory is not correct, but I am not sure where I am going wrong.
A simplified version of the code follow (also here: https://github.com/LenteDreyer/Tests.git )
Can someone see where I am going wrong?
class header file that save/loads the file
#ifndef __TESTS_MAP_HH__
#define __TESTS_MAP_HH__
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
typedef struct test_struct{
bool test_bool;
double test_double;
std::vector<double> test_vector;
} test_struct_t;
class map
{
private:
std::string m_path, m_str;
double m_double;
test_struct m_struct;
public:
map(const std::string& a_id);
void set_str(std::string a_str);
void set_double(double a_double);
void set_struct(test_struct a_struct);
void load_file();
void save_file() const;
void show_file() const;
~map();
};
#endif //__TESTS_MAP_HH__
class source file that save/loads the binary file
#include "map.hh"
map::map(const std::string& a_id)
{
m_path = a_id + ".bin";
m_str = "none";
m_double = 0.0;
m_struct = {false, 0.0};
}
void map::set_str(std::string a_str){
m_str = a_str;
}
void map::set_double(double a_double){
m_double = a_double;
}
void map::set_struct(test_struct a_struct){
m_struct = a_struct;
}
void map::load_file(){
std::ifstream l_inF;
l_inF.open(m_path.c_str(), std::ios::binary | std::ios::in);
l_inF.read((char*)&m_double,sizeof(double));
l_inF.read((char*)&m_struct,sizeof(test_struct_t));
size_t str_size;
l_inF.read((char*)&str_size, sizeof(str_size));
m_str.resize(str_size);
l_inF.read((char*)&m_str[0], str_size);
l_inF.close();
}
void map::save_file() const{
std::ofstream l_outF;
l_outF.open(m_path.c_str(), std::ios::binary | std::ios::out);
l_outF.write((char*)&m_double,sizeof(double));
l_outF.write((char*)&m_struct,sizeof(test_struct_t));
size_t str_size = m_str.size();
l_outF.write((char*)&str_size, sizeof(str_size));
l_outF.write((char*)&m_str[0], str_size);
l_outF.close();
}
void map::show_file() const{
std::cout << ">>-----------------------------------------------" << std::endl;
std::cout << ">> double : " << m_double << std::endl;
std::cout << ">> double : " << m_double << std::endl;
std::cout << ">> struct.bool : " << m_struct.test_bool << std::endl;
std::cout << ">> struct.double : " << m_struct.test_double << std::endl;
std::cout << ">> struct.vector : " << "size = " << m_struct.test_vector.size() << std::endl;
std::cout << ">> string : " << m_str << std::endl;
std::cout << ">>-----------------------------------------------" << std::endl;
}
map::~map(){}
main function case 1 works, and case 2 gives the segmentation fault.
#include "map.hh"
int main(int argc, char const *argv[])
{
std::string id = "mapfile";
int action = 0;
if(argc > 1) action = std::stoi(argv[1]);
else {
std::string input;
std::cout << "Enter case (1 or 2): ";
std::cin >> input;
action = std::stoi(input);
}
switch (action)
{
case 1:
{
// This works 100% (no errors and it saves/reads class perfectly)
std::vector<double> l_vect = {0.1, 0.0, 0.6};
test_struct save_struct = {true, 5.0, l_vect};
map test_save(id);
test_save.show_file();
test_save.set_double(8.0);
test_save.set_str("save this string");
test_save.set_struct(save_struct);
test_save.show_file();
test_save.save_file();
map test_load(id);
test_load.load_file();
test_load.show_file();
}
break;
case 2:
{
// gives segmentation error at the end of the program
map test_load(id);
test_load.load_file();
test_load.show_file();
}
break;
default:
break;
}
return 0;
}

No matching conversion for functional-style cast from 'B *' to 'std::shared_ptr<A>'

I have a simple appliction that tries to initialize a shared ptr.
#include <iostream>
#include <memory>
#include <algorithm>
class A {
public:
A(){
std::cout << "default ctor for A" << std::endl;
}
~A(){
std::cout << "default dtor for A" << std::endl;
}
};
class B : A{
B(){
std::cout << "default ctor for B" << std::endl;
}
~B(){
std::cout << "default dtor for B" << std::endl;
}
};
int main()
{
auto ap = std::shared_ptr<A>(new B());
return 0;
}
I am getting the error
No matching conversion for functional-style cast from 'B *' to 'std::shared_ptr<A>'
in this line
auto ap = std::shared_ptr(new B());
What am I doing wrong here?
Class B should be declared like
class B : public A{
public:
B(){
std::cout << "default ctor for B" << std::endl;
}
~B(){
std::cout << "default dtor for B" << std::endl;
}
};

I can't find where std::option comes useful

I found above code in this link and it tells that this example where std::option nicely fits!
class UserRecord
{
public:
UserRecord(const std::string& name, std::optional<std::string> nick, std::optional<int> age)
: mName{ name }, mNick{ nick }, mAge{ age }
{
}
friend std::ostream& operator << (std::ostream& stream, const UserRecord& user);
private:
std::string mName;
std::optional<std::string> mNick;
std::optional<int> mAge;
};
std::ostream& operator << (std::ostream& os, const UserRecord& user)
{
os << user.mName << ' ';
if (user.mNick) {
os << *user.mNick << ' ';
}
if (user.mAge)
os << "age of " << *user.mAge;
return os;
}
int main()
{
UserRecord tim{ "Tim", "SuperTim", 16 };
UserRecord nano{ "Nathan", std::nullopt, std::nullopt };
std::cout << tim << "\n";
std::cout << nano << "\n";
}
I created another one without optional which is below and i find it more easier than one which uses std::option.
I think the second version is more readable because no need to use std::nullopt
class UserRecord
{
public:
UserRecord(const std::string& name, std::string nick = "", int age = 0)
: mName{ name }, mNick{ nick }, mAge{ age }
{
}
friend std::ostream& operator << (std::ostream& stream, const UserRecord& user);
private:
std::string mName;
std::string mNick;
int mAge;
};
std::ostream& operator << (std::ostream& os, const UserRecord& user)
{
os << user.mName << ' ';
if (user.mNick != "") {
os << user.mNick << ' ';
}
if (user.mAge != 0)
os << "age of " << user.mAge;
return os;
}
int main()
{
UserRecord tim{ "Tim", "SuperTim", 16 };
UserRecord nano{ "Nathan" };
std::cout << tim << "\n";
std::cout << nano << "\n";
}
So, why do we need to use optional in general and specially in this case?

Function Pointers in C++ Class Files

I've been trying to work with function pointers for quite a bit now, and to no avail. I've been working with a few friends to create a C++ 11 library to make creating ASCII games easier, and I've personally been working on creating a menu class. The beef of the class is complete, but one issue - I can't get the buttons to call functions. I always get the error:
terminate called after throwing an instance of 'std::bad_function_call'
what(): bad_function_call
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Obviously the error lies somewhere in the pointers, but I can't solve it for the life of me. Thanks for the help in advance.
Menu.h
#ifndef MENU_H
#define MENU_H
using namespace std;
#include <functional>
#include <string>
#include <map>
class Menu {
public:
int numberOfOptions;
map<int, string> options;
int currentSelection;
string title;
Menu();
Menu(int initialNumberOfOptions, map<int, string> initialOptions, int initialSelection);
void display();
void waitForInput();
void attachOptionAction(int option, void (*function)());
private:
map<int, void (*std::function<void()>)> optionActions;
void executeOptionAction(int option);
};
#endif
Menu.cpp
#include "Menu.h"
#include <windows.h>
#include <iostream>
#include <conio.h>
Menu::Menu(int initialNumberOfOptions, map<int, string> initialOptions, int initialSelection) {
title = "";
numberOfOptions = initialNumberOfOptions;
options = initialOptions;
currentSelection = initialSelection;
}
void Menu::display() {
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0, 0});
for(int i = 0; i < 10; i++) {
cout << " " << endl;
}
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0, 0});
if(title != "") {
cout << title << endl << endl;
}
for(int i = 0; i < numberOfOptions; i++) {
if(i == currentSelection - 1) {
cout << "[ " << options[i] << " ]" << endl;
} else {
cout << options[i] << endl;
}
}
waitForInput();
}
void Menu::waitForInput() {
char input;
while(!kbhit());
input = getch();
if(input == 72 && currentSelection > 1) {
currentSelection--;
} else if (input == 80 && currentSelection < numberOfOptions) {
currentSelection++;
} else if (input == 13) {
if(currentSelection == 1) {
executeOptionAction(1);
}
return;
}
display();
}
void Menu::attachOptionAction(int option, std::function<void()> function) {
optionActions[option] = function;
}
void Menu::executeOptionAction(int option) {
(optionActions[option])();
}
test.cpp
#include "Menu.h"
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <map>
void test() {
cout << "Hello, World!";
}
int main() {
map<int, string> options;
options[0] = "Play";
options[1] = "Help";
options[2] = "Quit";
Menu menu(3, options, 1);
menu.title = "ASCII Game Library 2015";
menu.display();
void (*actionPointer)() = NULL;
menu.attachOptionAction(1, (*actionPointer));
return 0;
}
This is wrong. I'm not even sure what's that supposed to be.
map<int, void (*std::function<void()>)> optionActions;
It should be:
map<int, std::function<void()>> optionActions;
This here is also wrong. It would be correct if you hadn't imported std into your current namespace.
void attachOptionAction(int option, void (*function)());
It should be:
void attachOptionAction(int option, const std::function<void()> & action);
This here is also wrong. You can't name your argument function after you imported std into your namespace.
void Menu::attachOptionAction(int option, std::function<void()> function)
It should be:
void Menu::attachOptionAction(int option, const std::function<void()> & action)
This here is also wrong. You don't check if the function exists or that a valid function pointer was assigned to it. Which you haven't.
(optionActions[option])();
It should be:
// Attempt to find the action!
map<int, std::function<void()>>::iterator action = optionActions.find(option);
// Did we find anything?
if (action == optionActions.end())
{
return;
}
// Is the function assigned to this action valid?
if (action->second)
{
action->second();
}
You are attaching a null function pointer to an action and try to call it. And since there's no validation it does exactly that. Which is why you get that exception:
void (*actionPointer)() = NULL;
menu.attachOptionAction(1, (*actionPointer));
But I'm not even sure how even managed to compile it :/
EDIT:
I hope you can find this example to be informative on what you're looking for.
#include <map>
#include <string>
#include <cstdlib>
#include <iostream>
#include <functional>
class Menu
{
protected:
typedef std::function<int (Menu &)> Callback;
typedef std::map<int, Menu> SubMenus;
public:
Menu()
: m_Id(0), m_Name(""), m_Handler(nullptr)
{
}
Menu(int id, const std::string & name, Callback clbk)
: m_Id(id), m_Name(name), m_Handler(clbk)
{
}
Menu & operator [] (int id)
{
return m_Childrens.at(id);
}
int Enter()
{
int result = 0;
if (m_Handler)
result = m_Handler(*this);
return result;
}
void Insert(const Menu & menu)
{
m_Childrens[menu.m_Id] = menu;
}
void Insert(int id, const std::string & name, Callback clbk)
{
m_Childrens[id] = Menu(id, name, clbk);
}
void Remove(int id)
{
m_Childrens.erase(id);
}
int GetId() const
{
return m_Id;
}
const std::string & GetName() const
{
return m_Name;
}
const Callback & GetHandler() const
{
return m_Handler;
}
bool IsChildren(int id) const
{
return (m_Childrens.find(id) != m_Childrens.cend());
}
Menu & GetChildren(int id)
{
return m_Childrens.at(id);
}
const SubMenus & GetChildrens() const
{
return m_Childrens;
}
private:
int m_Id;
std::string m_Name;
Callback m_Handler;
SubMenus m_Childrens;
};
void ClearScreen()
{
system("cls");
}
int SharedMenuDisplay(const Menu & menu)
{
ClearScreen();
std::cout << "Welcome to " << menu.GetName() << std::endl;
for (const auto & m : menu.GetChildrens())
{
std::cout << "> " << m.second.GetId() << " - " << m.second.GetName() << std::endl;
}
std::cout << "> 0 - Go Back" << std::endl;
std::cout << "Please select a sub menu: ";
int choice;
std::cin >> choice;
return choice;
}
int Menu_Home(Menu & menu)
{
int choice;
int result = 0;
do {
ClearScreen();
std::cout << "Welcome to " << menu.GetName() << std::endl;
for (const auto & m : menu.GetChildrens())
{
std::cout << "> " << m.second.GetId() << " - " << m.second.GetName() << std::endl;
}
std::cout << "> 0 - To Leave" << std::endl;
std::cout << "Please select a sub menu: ";
std::cin >> choice;
if (choice != 0 && menu.IsChildren(choice))
result = menu.GetChildren(choice).Enter();
} while (choice != 0);
return result;
}
int Menu_A(Menu & menu)
{
int choice;
int result = 0;
do {
choice = SharedMenuDisplay(menu);
if (choice != 0 && menu.IsChildren(choice))
result = menu.GetChildren(choice).Enter();
} while (choice != 0);
return result;
}
int Menu_A_SubMenu_X(Menu & menu)
{
ClearScreen();
std::cout << "You have selected " << menu.GetName() << std::endl;
std::cout << "> Type something and press Enter to go back..." << std::endl;
std::string str;
std::cin >> str;
return 0;
}
int Menu_A_SubMenu_Y(Menu & menu)
{
ClearScreen();
std::cout << "You have selected " << menu.GetName() << std::endl;
std::cout << "> Type something and press Enter to go back..." << std::endl;
std::string str;
std::cin >> str;
return 0;
}
int Menu_A_SubMenu_Z(Menu & menu)
{
ClearScreen();
std::cout << "You have selected " << menu.GetName() << std::endl;
std::cout << "> Type something and press Enter to go back..." << std::endl;
std::string str;
std::cin >> str;
return 0;
}
int Menu_B(Menu & menu)
{
int choice;
int result = 0;
do {
choice = SharedMenuDisplay(menu);
if (choice != 0 && menu.IsChildren(choice))
result = menu.GetChildren(choice).Enter();
} while (choice != 0);
return result;
}
int Menu_B_SubMenu_X(Menu & menu)
{
ClearScreen();
std::cout << "You have selected " << menu.GetName() << std::endl;
std::cout << "> Type something and press Enter to go back..." << std::endl;
std::string str;
std::cin >> str;
return 0;
}
int Menu_B_SubMenu_Y(Menu & menu)
{
ClearScreen();
std::cout << "You have selected " << menu.GetName() << std::endl;
std::cout << "> Type something and press Enter to go back..." << std::endl;
std::string str;
std::cin >> str;
return 0;
}
int Menu_B_SubMenu_Z(Menu & menu)
{
ClearScreen();
std::cout << "You have selected " << menu.GetName() << std::endl;
std::cout << "> Type something and press Enter to go back..." << std::endl;
std::string str;
std::cin >> str;
return 0;
}
int Menu_C(Menu & menu)
{
ClearScreen();
std::cout << "You have selected " << menu.GetName() << std::endl;
std::cout << "> Type something and press Enter to go back..." << std::endl;
std::string str;
std::cin >> str;
return 0;
}
int main(int argc, char **argv)
{
Menu home(-1, "Home", &Menu_Home);
home.Insert(1, "Menu Item A", &Menu_A);
home.Insert(2, "Menu Item B", &Menu_B);
home.Insert(3, "Menu Item C", &Menu_C);
home.GetChildren(1).Insert(1, "Sub Menu Item X", &Menu_A_SubMenu_X);
home.GetChildren(1).Insert(2, "Sub Menu Item Y", &Menu_A_SubMenu_Y);
home.GetChildren(1).Insert(3, "Sub Menu Item Z", &Menu_A_SubMenu_Z);
home[2].Insert(1, "Sub Menu Item X", &Menu_B_SubMenu_X);
home[2].Insert(2, "Sub Menu Item Y", &Menu_B_SubMenu_Y);
home[2].Insert(3, "Sub Menu Item Z", &Menu_B_SubMenu_Z);
return home.Enter();
}

Want to reset integers using virtual class function

The function I want works within the class butt won't apply to main. Must maintain the initial (Entity *entity = new Nummchange(flarb);)
#include <iostream>
using namespace std;
class Entity
{
public:
Entity(){}
~Entity(){}
virtual int reset(int NUMM) = NULL;
protected:
private:
};
class Nummchange : public Entity
{
public:
Nummchange(int NUMM);
~Nummchange();
int reset(int NUMM);
protected:
private:
int numm;
};
Nummchange::Nummchange(int NUMM)
{
}
Nummchange::~Nummchange()
{
}
int Nummchange::reset(int NUMM)
{
numm = 50;
NUMM = numm;
std::cout << "\nnumm+++++++"<< numm << "\n" << std::endl;
return numm;
}
int main()
{
int flarb = 50;
Entity *entity = new Nummchange(flarb);
while (flarb >= 0)
{
flarb--;
cout << flarb;
if(flarb == 0)
{
entity->reset(flarb);
std::cout << "flarb+++++++"<< flarb << "\n" << std::endl;
}
}
system("pause");
return 0;
}
Success is if the while loop continues perpetually.
int reset(int NUMM); method should take reference of integer type as below.
int reset(int &NUMM);
Make sure that you change the parameter to be reference of integer in all the three places of the method use in the program.