I've looked around at multiple questions on this topic on SO as well as several references and have not seen this issue come up anywhere.
When my instance of Derived calls Base::GetValue() (which calls the virtual doGetValue(), defined in Derived and in Base), Base::doGetValue() is called instead of Derived::doGetValue(). Why is that and what do I need to do differently?
Is it because Derived::doGetValue() is private instead of protected? That seems to me to be the most likely explanation, but I haven't seen that explicitly stated anywhere that I've looked so far.
Here is my code on coliru.
Below is my code:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <memory>
using namespace std;
class Base
{
private:
virtual string doGetname( ) const { return "Base"; };
protected:
virtual void doGetValue( map<string,string> &ds, const bool include ) const;
inline void doGetValue( map<string,string> &ds ) const { doGetValue(ds, true); };
public:
string GetValue( ) const;
string GetName( ) const { return doGetname(); };
};
class Derived : public Base
{
private:
virtual void doGetValue( map<string,string> &ds ) const;
virtual string doGetname( ) const { return "Derived"; };
};
struct generate_value_from_map : std::unary_function<void, void>
{
generate_value_from_map( string *_val, const string assignment = " " ):val(_val)
{
count = 0;
insert = (*_val);
first = "(";
second = ") "+assignment+" (";
}
void operator() (pair<const string,string> &i)
{
first += ( count > 0 ? "," : "" ) + i.first;
second += ( count > 0 ? "," : "" ) + i.second;
(*val) = insert + first + second + ")";
++count;
}
private:
int count;
string *val;
string insert;
string first;
string second;
};
string Base::GetValue( ) const
{
string ret_val = "name is: " + GetName() + " \n";
map<string,string> ret_map;
this->doGetValue(ret_map);
for_each(ret_map.begin(), ret_map.end(), generate_value_from_map(&ret_val));
return ret_val;
}
void Base::doGetValue( map<string,string> &ds, const bool include ) const
{
//base implementation
//fills ds with values from Base
ds["type"] = "Base";
ds["id"] = "Id";
}
void Derived::doGetValue( map<string,string> &ds ) const
{
Base::doGetValue( ds );
//derived implementation
//fills ds with values from Derived
ds["type"] = "Derived";
ds["name"] = "Name";
}
int main()
{
shared_ptr<Derived> obj ( new Derived() );
string val = obj->GetValue();
cout << val;
//do stuff with val
}
I tried to include all the specifics of my issue, excluding some of the delphi-inherited features of my compiler (RAD Studio XE4).
The definitions of doGetValue are different between base and derived.
Base:
virtual void doGetValue( map<string,string> &ds, const bool include ) const;
inline void doGetValue( map<string,string> &ds ) const { doGetValue(ds, true); };
Derived:
virtual void doGetValue( map<string,string> &ds ) const;
In the base the function is not virtual.
Related
I need to implement one abstract class, three its concrete subclasses, class which goal to create one of this three classes instances and last class executor of three classes. Requirements are c++98, and not to use if/elseif/else to construct class instance, like i did in a Maker class method make Form. What mechanism i need to avoid if / elseif / else?
For example:
test.h
#ifndef TEST_H
#define TEST_H
#include <iostream>
class Executor {
private:
const std::string name;
public:
Executor(const std::string &name = "") {};
const std::string getname() const {return name;}
};
class BForm {
private:
const std::string _name;
public:
BForm(const std::string &name = "") : _name(name) {};
virtual ~BForm() {};
virtual void execute(const Executor &src) = 0;
const std::string getname() {return _name;}
virtual const std::string gettarget() = 0;
};
class Form1 : public BForm{
private:
std::string _target;
public:
Form1(const std::string &target = "") : BForm("form1"), _target(target) {};
virtual ~Form1() {};
virtual void execute(const Executor &src) {
std::cout << src.getname() << " exec form1 target:" << _target << std::endl;
}
virtual const std::string gettarget() {return _target;}
};
class Form2 : public BForm {
private:
std::string _target;
public:
Form2(const std::string &target = "") : BForm("form2"), _target(target) {};
virtual ~Form2() {};
virtual void execute(const Executor &src) {
std::cout << src.getname() << " exec form2 target:" << _target << std::endl;
};
virtual const std::string gettarget() {return _target;}
};
class Form3 : public BForm {
private:
std::string _target;
public:
Form3(const std::string &target = "") : BForm("form3"), _target(target) {};
virtual ~Form3() {};
virtual void execute(const Executor &src) {
std::cout << src.getname() << " exec form3 target:" << _target << std::endl;
};
virtual const std::string gettarget() {return _target;}
};
class Maker {
public:
BForm *makeForm(const std::string &name, const std::string &target)
{
/* need to avoid */
if (name == "form1")
return new Form1(target);
else if (name == "form2")
return new Form2(target);
else
return new Form3(target);
}
};
#endif
main.cpp
#include "test.h"
int main() {
Maker maker;
BForm *form;
Executor exec("executor");
form = maker.makeForm("form1", "A");
std::cout << form->getname() << " " << form->gettarget() << std::endl;
form->execute(exec);
delete form;
return (0);
}
You could typedef a pointer to function and then use a map from string to this type (pointer to function). And then use your parameter with indexer syntax to access the correct pointer to function.
Here is an example:
#include <iostream>
#include <map>
// The class definitions with a virtual function hello() common to all
class Base { public: virtual void hello() = 0; };
class Derived1 : public Base { public: void hello() { std::cout << "Derived1"; } };
class Derived2 : public Base { public: void hello() { std::cout << "Derived2"; } };
// The object making functions
Base* Maker1() { return new Derived1; }
Base* Maker2() { return new Derived2; }
int main()
{
// In C++98, without auto, it's worthwhile to typedef complicated types.
// The first one is a function type returning a pointer to Base...
typedef Base* MakerT();
// ... the second one is a map type projecting strings to such function pointers
typedef std::map<std::string, MakerT*> StrToMakerT;
/// The actual map projecting strings to maker function pointers
StrToMakerT strToMaker;
// Fill the map
strToMaker["D1"] = &Maker1;
strToMaker["D2"] = &Maker2;
// user input
std::string choice;
// as long as output works, input works, and the user didn't say "Q":
while (std::cout << "Please input 'D1' or 'D2' or 'Q' for quit: "
&& std::cin >> choice
&& choice != "Q")
{
// Prevent adding new entries to the map foir unknown strings
if (strToMaker.find(choice) != strToMaker.end())
{
// Simply look the function up again, the iterator type is too
// cumbersome to write in C++98
Base* b = (*strToMaker[choice])();
b->hello();
std::cout << '\n';
delete b;
}
else
{
std::cout << "Didn't find your choice, try again.\n";
}
}
std::cout << "Thank you, good bye\n";
}
Two classes: Data is parent and DerivedData is child. Why does cout output "Data"?
class Data {
protected:
int _value {};
public:
Data(int value) : _value{ value } { }
std::string getName() const {
return "Data";
}
int getValue() const {
return _value;
}
void setValue(const int i) {
_value = i;
}
};
class DerivedData: public Data {
public:
DerivedData(int value) : Data{ value } { }
std::string getName() const {
return "DerivedData";
}
int getValueDoubled() const {
return _value * 2;
}
};
DerivedData dd{ 5 };
Data d = dd;
Data& rd = dd;
cout << rd.getName() << endl;
This code will output "Data", but why?
You are not using virtual so it is kinda redefinition of the parent function which you think is polymorphsim but it is not.
When it execute this line of code Data& rd = dd; you had expected to be printed DerviedData but this did not happen because your function was not virtual, and base class do not know you are overriding the getName method in derived class.
So to fix this issue need to declare your function virtual:
virtual std::string getName() const { return "Data"; } //Data
And in DerivedData:
std::string getName() const override { return "DerivedData"; } //DerivedData
Now this will behave the way you'd expected.
I got a template class Atlas that will store objects of Animal class and derived classes of Animal;
here's the code:
#include <iostream>
#include <assert.h>
#include <list>
using namespace std;
class Animal {
protected:
std::string m_name;
Animal (std::string name): m_name {name} {}
public:
virtual std::string regn() const { return "???"; }
virtual ~Animal(){
cout << "Destructor animal"<<'\n';}
};
class Nevertebrate : public Animal{
public:
virtual std::string regn() const { return "nevertebrate";}
virtual ~Nevertebrate();
};
class Vertebrate: public Animal {
protected:
/* std::string m_name;
Vertebrate (std::string name)
:m_name {name} {} */
Vertebrate (std::string name)
: Animal {name} {}
public:
virtual std::string regn() const { return "vertebrate";}
virtual ~Vertebrate(){
cout<<"Destructor vertebrate"<<'\n';};
};
class bird: public Vertebrate {
public:
bird(std::string name)
: Vertebrate{ name }{}
void set_name (std::string nume){
m_name = nume;}
std::string get_name(){
return m_name;}
virtual std::string regn() const {return "pasare";}
virtual ~bird (){
cout << "destructor bird"<<'\n';}
};
template <class T>
class Atlas
{
private:
int m_length{};
T* m_data{};
public:
void SetLength(int j);
Atlas(int length)
{
assert(length > 0);
m_data = new T[length]{};
m_length = length;
}
Atlas(const Atlas&) = delete;
Atlas& operator=(const Atlas&) = delete;
~Atlas()
{
delete[] m_data;
}
void erase()
{
delete[] m_data;
m_data = nullptr;
m_length = 0;
}
T& operator[](int index)
{
assert(index >= 0 && index < m_length);
return m_data[index];
}
int getLength() const;
};
template <class T>
int Atlas<T>::getLength() const
{
return m_length;
}
template <class T>
void Atlas<T>::SetLength(int j){m_length = j;
}
int main()
{
Atlas<Bird> AtlasBird(10);
Bird b;
AtlasBird.SetLength(11);
AtlasBird[10] = b --- it gets a memoryleak from here.
return 0;
}
I want to overload the += operator so that i can insert a new object into my Atlas, (e.g. AtlasAnimal).
I tried with the SetLength function to increase the length, (e.g. AtlasAnimal.SetLength(11)) but when i try to assign AtlasAnimal[10] an object (e.g. Bird b) it drops a memory leak.
I'm sorry if there was a similar question answered, but i couldn't find anything that helps
Hi i am trying to create a simple ORM in c++ for a project. For this example assuming a simple class as
class userProfile: public BaseOrm
{
public:
string username;
string email;
};
Now base orm has a method save() and migrate(). What i want is when a person calls migrate() all the schema , in this case username and email are populated as db tables and on save they persist on database.
What i am having problem with is how do i get what all fields are defined in the class, like in this example username and email and also there types, string in this case. Any help would be appreciated.
I know there is no reflection in c++, so i don't actually care about the variable name but more on the number of variables and there types to map them with DB.
adding reflection to c++ is not insanely difficult but it does require a reasonably good knowledge of template type deduction and some careful planning.
In this working example I have made a start for you. This framework supports writing the members out to a "statement" class (modelling a database prepared statement).
Similar techniques can be used to build out the SQL generation for CRUD.
No doubt there are already libraries that do this for you...
#include <iostream>
#include <iomanip>
#include <string>
#include <tuple>
#include <utility>
using namespace std;
struct statement
{
void setString(int index, const std::string& value)
{
std::cout << "setting index " << index << " to value " << std::quoted(value) << std::endl;
}
};
struct BaseOrm
{
virtual void serialise(statement& stmt) const = 0;
};
template<class Class>
struct class_tag {
using type = Class;
};
template<const char* Name>
struct name_tag {
static constexpr const char* name() { return Name; }
};
namespace detail {
struct reflection_item_concept
{
virtual const std::string& name() const = 0;
virtual std::string to_archive_string(const void* object) const = 0;
virtual void from_archive_string(void* object, const std::string& as) const = 0;
};
template<class T>
std::string to_archive_string_impl(const T& val) {
return std::to_string(val);
}
const std::string& to_archive_string_impl(const std::string& s) {
return s;
}
template<class NameTag, class Class, class Type>
struct reflection_item : reflection_item_concept
{
reflection_item(Type Class::* mfp) : mfp(mfp) {}
static const class_tag<Class> class_info() { return {}; };
static const char* raw_name() { return NameTag::name(); };
// concept implementation
const std::string& name() const override {
static const std::string s = raw_name();
return s;
}
std::string to_archive_string(const void* object) const override
{
auto& val = (*reinterpret_cast<const Class*>(object)).*mfp;
return to_archive_string_impl(val);
}
void from_archive_string(void* item, const std::string& as) const override
{
// similar mechanism here
}
Type Class::* mfp;
};
}
template<class NameTag, class Class, class Type>
constexpr auto reflection_item(NameTag, Type Class::* mp)
{
return detail::reflection_item<NameTag, Class, Type> { mp };
}
struct class_reflection_concept
{
virtual void serialise(const void* object, statement& stmt) const = 0;
};
namespace detail {
template<class ClassTag, class...ReflectionItems>
struct reflection_impl : class_reflection_concept
{
reflection_impl(ReflectionItems...refs)
: _reflectors(std::make_tuple(refs...))
{}
template<std::size_t...Is>
void serialise_impl(std::index_sequence<Is...>, const void* object,
statement& stmt) const
{
using expand = int[];
void(expand{
0,
(stmt.setString(Is + 1, std::get<Is>(_reflectors).to_archive_string(object)),0)...
});
}
void serialise(const void* object, statement& stmt) const override
{
serialise_impl(std::make_index_sequence<sizeof...(ReflectionItems)>(),
object, stmt);
}
std::tuple<ReflectionItems...> _reflectors;
};
}
template<class ClassTag, class...ReflectionItems>
auto& make_reflection(ClassTag tag, ReflectionItems...items)
{
static const detail::reflection_impl<ClassTag, ReflectionItems...> _ { items... };
return _;
}
const char txt_username[] = "username";
const char txt_email[] = "email";
const char txt_x[] = "x";
class userProfile: public BaseOrm
{
public:
string username = "test username";
string email = "noone#nowhere.com";
int x = 10;
// implement serialisation
void serialise(statement& stmt) const override
{
reflection.serialise(this, stmt);
}
static const class_reflection_concept& reflection;
};
const class_reflection_concept& userProfile::reflection =
make_reflection(class_tag<userProfile>(),
reflection_item(name_tag<txt_username>(), &userProfile::username),
reflection_item(name_tag<txt_email>(), &userProfile::email),
reflection_item(name_tag<txt_x>(), &userProfile::x));
int main()
{
userProfile x;
statement stmt;
x.serialise(stmt);
}
expected results:
setting index 1 to value "test username"
setting index 2 to value "noone#nowhere.com"
setting index 3 to value "10"
What I understand is that you want a generic behaviour for classes which have a variable set of fields.
I suggest you to create a "field" interface which will be stored in your base class with a container (for example a map of [fieldName, fieldInterface]). You still have to implement a behaviour for each field's type, but then you can create any class derived from the base class which have a dynamic set of field.
Here is an example :
#include <iostream>
#include <map>
using namespace std;
//the "Field" interface
class IFieldOrm
{
public:
virtual ~IFieldOrm() {}
virtual void save() = 0;
virtual void migrate() = 0;
};
//your base class
class BaseOrm
{
public:
virtual ~BaseOrm();
virtual void save();
virtual void migrate();
protected:
map<string, IFieldOrm*> m_fields; //prefer a smart pointer if you don't want to mess with raw pointer
};
//base class implementation
void BaseOrm::save()
{
for(auto& f : m_fields)
f.second->save();
}
void BaseOrm::migrate()
{
for(auto& f : m_fields)
f.second->migrate();
}
//don't forget to free your "fields" pointers if you have raw pointers
BaseOrm::~BaseOrm()
{
for(auto& f : m_fields)
delete f.second;
}
//then implement your basic types
//(like string, int, ..., whatever type you want to store in your database)
class StringFieldOrm : public IFieldOrm
{
public:
StringFieldOrm(const string& value) : m_value(value) {}
virtual void save();
virtual void migrate();
private:
string m_value;
};
void StringFieldOrm::save()
{
cout << "Save value " << m_value << endl;
//save stuff...
}
void StringFieldOrm::migrate()
{
cout << "Migrate value " << m_value << endl;
//migrate stuff...
}
class IntFieldOrm : public IFieldOrm
{
public:
IntFieldOrm(int& value) : m_value(value) {}
virtual void save();
virtual void migrate();
private:
int m_value;
};
void IntFieldOrm::save()
{
cout << "Save value " << m_value << endl;
//save stuff...
}
void IntFieldOrm::migrate()
{
cout << "Migrate value " << m_value << endl;
//migrate stuff
}
//and finally implement your final class
//note that this object can be "dynamically extended" by inserting new fields,
//you may want to prevent that and I can think of a solution if you want to
class UserProfile: public BaseOrm
{
public:
UserProfile(const string& username, const string& email, int age);
};
UserProfile::UserProfile(const string& username, const string& email, int age)
{
m_fields["username"] = new StringFieldOrm(username);
m_fields["email"] = new StringFieldOrm(email);
m_fields["age"] = new IntFieldOrm(age);
}
int main(int argc, char* argv[])
{
UserProfile user = UserProfile("Batman", "bw#batmail.com", 30);
user.save();
return 0;
}
create a userProfile variable and access them:
userProfile user;
int main(){
std::cout << user.username;
std::cout << user.email ;
}
this is how you would access them, except for different reasons, not printing them to the screen.
Consider the following example:
struct MyStruct {
int a;
int b;
};
I can use macros to set a member from an instance of the struct by doing this:
#define setVar(x,y) instance.x = y
then in any function I can say:
setVar(a, 4)
How can I send in a as a string to the macro? Is that also possible?
setVar("a", 4)
EDIT: There are a bunch of predefined structs with members that are all of type double. I only know what struct I am using by an XML config file that is passed in. After parsing, I have a bunch of strings that are a list of all the data members and values that need to be set. I need to use this list to set values for each of the members in the struct.
It is only possible if you define the struct itself using some macro, for example:
#define MY_STRUCT_STRUCTURE FIELD(a) FIELD(b) FIELD(d) FIELD(e) FIELD(f)
struct MyStruct {
# define FIELD(name) int name;
MY_STRUCT_STRUCTURE
# undef FIELD
bool setVar(char* fieldname, int val)
{
# define FIELD(name) if(strcmp(#name,fieldname)==0){name=val; return true;};
MY_STRUCT_STRUCTURE
# undef FIELD
return false; // name not found
}
};
int main()
{
MyStruct s;
s.setVar("a",1);
s.setVar("b",2);
s.setVar("f",100);
}
I have coded some quick and dirty code, but could give you some ideas, hope that helps. The main trick here is too use unions.
struct MyStruct
{
int a;
double b;
MyStruct()
: a(0), b(0) {}
};
MyStruct instance;
union value
{
long value_a;
double value_d;
} myvalue;
void blah_a(value v)
{
instance.a = v.value_a;
}
void blah_b(value v)
{
instance.b = v.value_d;
}
struct
{
(void)(*fn)(value);
const char* key;
}
lookup_table[] =
{
{ &blah_a, "a" },
{ &blah_b, "b" }
};
void setVar(const char* c, value v)
{
for (int i = 0; lookup_table[i].fn; i++)
if (c == lookup_table[i].key)
(*(lookup_table[i].fn))(v);
}
int main(int argc, char* argv[])
{
value v;
v.value_a = 6;
setVar("a", v);
return 0;
}
Might not be what you are looking for but an alternative solution to macros etc.. would just be some encapsulation and OO design. You can change the Field class to a template later and you will be able to represent anything basically.
You can create a class
class Field
{
public:
Field(const std::string& name, const std::string& type);
virtual ~Field(void);
std::string toString() const;
std::string getName() const;
int getValue() const { return value };
private:
std::string name;
std::string type;
int value;
};
And then a structure class
#pragma once
#include <boost/ptr_container/ptr_deque.hpp>
#include <string>
class Field;
class MyStructure
{
public:
typedef boost::ptr_deque<Field> FieldList;
typedef FieldList::iterator FieldListIter;
typedef FieldList::auto_type AutoField;
MyStructure(void);
MyStructure(const std::string& name);
virtual ~MyStructure(void);
void setName(const std::string& name);
std::string getName() const;
void addField( std::auto_ptr<Field> field );
std::string getFieldValue( const std::string& name ) const;
MyStructure::AutoField removeField( const std::string& name );
std::string toString(void) const;
private:
std::string struct_name;
FieldList fields;
};
And then to use it:
auto_ptr<MySructure> struct_a(new MySructure("StructName1",0) );
struct_a->addField( auto_ptr<Field> ( new Field( "Field1", 1 ) ) );
struct_a->addField( auto_ptr<Field> ( new Field( var_str1, 2) ) );
struct_a->addField( auto_ptr<Field> ( new Field( getName(), getVal() ) ) );