Question about polymorphism and mulitipule inheritance - c++

I hope to store the data in three different ways:
1.store to a std::string
2.write to file descriptor
3.both of the above
And I hope to use a uniform interface for these three different methods.
I wrote a simple code sippet to achieve the said goals. The first & second are easy indeed, but for the third I am stuck.
Please pay attention to the comment in the code snippet below, which is what the compiler complains if STORE_BY_FD_AND_STRING is defined.
Here is the code snippet:
#include <memory>
#include <iostream>
#include <unistd.h>
class DataStorage {
public:
DataStorage(int total_count):total_count_(total_count){};
virtual int Store(const char *buffer, int count) = 0;
virtual ~DataStorage(){};
protected:
int total_count_;
};
class DataStorageByStr : public DataStorage {
public:
DataStorageByStr(std::string &str) : str_(str), DataStorage(0){};
int Store(const char *buffer, int count)
{
str_ += std::string(buffer, count);
total_count_ += count;
return 0;
};
protected:
std::string &str_;
};
class DataStorageByFd : public DataStorage {
public:
DataStorageByFd(int &fd):fd_(fd), DataStorage(0){};
int Store(const char *buffer, int count)
{
int ret = write(fd_, buffer, count);
if(ret > 0)
{
total_count_ += ret;
}
return ret;
};
protected:
int &fd_;
};
class DataStorageByStrAndFd : public DataStorageByStr, public DataStorageByFd {
public:
DataStorageByStrAndFd(std::string &str, int &fd):DataStorageByStr(str), DataStorageByFd(fd) {}
int Store(const char *buffer, int count)
{
int ret1 = DataStorageByStr::Store(buffer, count);
int ret2 = DataStorageByFd::Store(buffer, count);
return ((0==ret1) && (0==ret2))?0:-1;
}
};
int StoreSomeData(DataStorage *pstorage, const std::string data_to_store)
{
return pstorage->Store(data_to_store.data(), data_to_store.length());
}
int main()
{
{
std::string str{"storing the string to std::string works !"};
std::string data;
DataStorage *pstorage = new DataStorageByStr(data);
StoreSomeData(pstorage, str);
std::cout << data << std::endl;
}
{
std::string str{"storing the string to fd works !"};
int fd = 1;
DataStorage *pstorage = new DataStorageByFd(fd);
StoreSomeData(pstorage, str);
}
#ifdef STORE_BY_FD_AND_STRING
{
std::string str{"thanks for your attention for this matter!"};
std::string data;
int fd = 1;
DataStorage *pstorage = new DataStorageByStrAndFd(str, fd); //The compiler complain that 'DataStorage' is an ambiguous base of 'DataStorageByStrAndFd'
StoreSomeData(pstorage, str);
}
#endif
}
Any sugestion to achieve all the aforementioned goals?

Thanks to #Sam Varshavchik #Adrian Mole. This code snippet works.
#include <memory>
#include <iostream>
#include <unistd.h>
class DataStorage {
public:
DataStorage(int total_count):total_count_(total_count){};
virtual int Store(const char *buffer, int count) = 0;
virtual ~DataStorage(){};
protected:
int total_count_;
};
class DataStorageByStr : virtual public DataStorage {
public:
DataStorageByStr(std::string &str) : str_(str), DataStorage(0){};
int Store(const char *buffer, int count)
{
str_ += std::string(buffer, count);
total_count_ += count;
return 0;
};
protected:
std::string &str_;
};
class DataStorageByFd :virtual public DataStorage {
public:
DataStorageByFd(int &fd):fd_(fd), DataStorage(0){};
int Store(const char *buffer, int count)
{
int ret = write(fd_, buffer, count);
if(ret > 0)
{
total_count_ += ret;
}
return ret;
};
protected:
int &fd_;
};
class DataStorageByStrAndFd : public DataStorageByStr, public DataStorageByFd {
public:
DataStorageByStrAndFd(std::string &str, int &fd):DataStorageByStr(str), DataStorageByFd(fd), DataStorage(0)
{
}
int Store(const char *buffer, int count)
{
int ret1 = DataStorageByStr::Store(buffer, count);
int ret2 = DataStorageByFd::Store(buffer, count);
return ((0==ret1) && (0==ret2))?0:-1;
}
};
int StoreSomeData(DataStorage *pstorage, const std::string data_to_store)
{
return pstorage->Store(data_to_store.data(), data_to_store.length());
}
int main()
{
{
std::string str{"storing the string to std::string works !"};
std::string data;
DataStorage *pstorage = new DataStorageByStr(data);
StoreSomeData(pstorage, str);
std::cout << data << std::endl;
}
{
std::string str{"storing the string to fd works !"};
int fd = 1;
DataStorage *pstorage = new DataStorageByFd(fd);
StoreSomeData(pstorage, str);
}
#ifndef STORE_BY_FD_AND_STRING
{
std::string str{"thanks for your attention for this matter!"};
std::string data;
int fd = 1;
DataStorage *pstorage = new DataStorageByStrAndFd(str, fd); //The compiler complain that 'DataStorage' is an ambiguous base of 'DataStorageByStrAndFd'
StoreSomeData(pstorage, str);
}
#endif
}
Explanation:
Virtual inheritance is a C++ technique that ensures only one copy of a base class's member variables are inherited by grandchild derived classes. Without virtual inheritance, if two classes B and C inherit from a class A, and a class D inherits from both B and C, then D will contain two copies of A's member variables: one via B, and one via C. These will be accessible independently, using scope resolution.
Instead, if classes B and C inherit virtually from class A, then objects of class D will contain only one set of the member variables from class A.
This feature is most useful for multiple inheritance, as it makes the virtual base a common subobject for the deriving class and all classes that are derived from it. This can be used to avoid the diamond problem by clarifying ambiguity over which ancestor class to use, as from the perspective of the deriving class (D in the example above) the virtual base (A) acts as though it were the direct base class of D, not a class derived indirectly through a base (B or C).

Related

C++ type casting alternative to virtual methods

In C++ you can use virtual methods to have following code work as you expect:
#include <iostream>
#include <string>
class BaseClass {
public:
virtual std::string class_name() const { return "Base Class"; }
};
class FirstClass : public BaseClass {
int value = 1;
public:
std::string class_name() const { return "FirstClass"; }
};
class SecondClass : public BaseClass {
long long value = -1;
public:
std::string class_name() const { return "SecondClass"; }
};
int main() {
const int array_size = 5;
const bool in_first_mode = true;
void *data;
int sample_size;
if (in_first_mode) {
data = new FirstClass[array_size];
sample_size = sizeof(FirstClass);
} else {
data = new SecondClass[array_size];
sample_size = sizeof(SecondClass);
}
// this is class-independent code
for (int index = 0; index < array_size; ++index) {
BaseClass *pointer = static_cast<BaseClass*>(data + index * sample_size);
std::cout << pointer->class_name() << std::endl;
}
return 0;
}
This will work correctly for both in_first_mode = true and in_first_mode = false.
So, basically, when you want to write code that works for both classes you can just use pointer to the BaseClass.
But what if you already given data buffer, filled with data of type TypeOne, TypeTwo, TypeThree or TypeFour, and in runtime you know that type, which stored in int type. Problem is that TypeOne, TypeTwo, TypeThree and TypeFour have not inherited from one base class. In my case, actually, they are structs from 3rd party library, which is already compiled C-compatible library, so I can not modify it. I want to get something like pointer from the example above, but problem arises with identifying what C++ type should have this pointer.
It there a more elegant type-casting alternative to making C++ class wrappers to these four types (which gives something similar to the example above), and to making pointer be void * and necessity of
if (type == 1) {
TypeOne *type_one_pointer = static_cast<TypeOne*>(pointer);
// do something
} else if (type == 2) {
/* ... */
}
every time I use pointer?
If the classes are unrelated, you can store them in a std::variant (or use Boost.Variant if your compiler is not C++17 compliant) and access the value with a visitor. This is more flexible than templates, as it allows you to include types with a different interface in the variant type.
For example (I did not compile this code):
#include <iostream>
#include <string>
#include <variant>
#include <vector>
struct TypeOne {
std::string class_name() const { return "Type one"; }
};
struct TypeTwo {
int value = 1;
std::string class_name() const { return "Type two"; }
};
struct TypeThree {
long long value = -1;
// note the different function signature
static std::string class_name() { return "Type three"; }
};
struct TypeFour {
std::string getMyClassName() const { return "Type four"; }
};
struct Visitor {
template <class T>
void operator ()(T&& value) const {
std::cout << value.class_name() << std::endl;
}
// special case
void operator ()(const TypeFour& value) const {
std::cout << value.getMyClassName() << std::endl;
}
};
int main() {
typedef std::variant<TypeOne, TypeTwo, TypeThree, TypeFour> Variant;
std::vector<Variant> values;
values.emplace_back(TypeOne{});
values.emplace_back(TypeTwo{});
values.emplace_back(TypeThree{});
values.emplace_back(TypeFour{});
for (const auto& var : values) {
std::visit(Visitor{}, var);
}
}
Thanks to #ForEveR, I find the solution. I need to use templates.
It means that if in the example above FirstClass and SecondClass would have no BaseClass one can do so:
#include <iostream>
#include <string>
class FirstClass {
int value = 1;
public:
std::string class_name() const { return "FirstClass"; }
};
class SecondClass {
long long value = -1;
public:
std::string class_name() const { return "SecondClass"; }
};
template <typename T>
void do_my_stuff(void* void_pointer) {
T *pointer = static_cast<T*>(void_pointer);
std::cout << pointer->class_name() << std::endl;
}
int main() {
const int array_size = 5;
const bool in_first_mode = true;
void *data;
int sample_size;
if (in_first_mode) {
data = new FirstClass[array_size];
sample_size = sizeof(FirstClass);
} else {
data = new SecondClass[array_size];
sample_size = sizeof(SecondClass);
}
for (int index = 0; index < array_size; ++index) {
if (in_first_mode) {
do_my_stuff<FirstClass>(data + index * sample_size);
} else {
do_my_stuff<SecondClass>(data + index * sample_size);
}
}
return 0;
}

Constructor in base and derived class

Program works but I am not sure what is wrong with constructor since every time program runs it gets this error "warning: base class 'Alat' is uninitialized when used here to access 'Alat::ime' [-Wuninitialized]". I suppose it's something wrong how I called a constructor from base class but I am not sure what is problem. Really need help, tnx in advance.
#include <iostream>
#include <string>
using namespace std;
class Alat{
protected:
string ime;
int serBr;
int cena;
public:
void setIme(string i);
string getIme();
void setSerBr(int sb);
int getSerBr();
void setCena(int c);
int getCena();
Alat();
Alat(string i, int sb, int c)
:ime(i),
serBr(sb),
cena(c)
{}
void info();
~Alat();
};
#include "Alat.h"
class Rucni : public Alat{
protected:
int minGodKor;
public:
Rucni():Alat(ime, serBr, cena) //I think here is problem, is it wrong called?
{}
int getminGodKor();
void setminGodKor(int min);
void info();
~Rucni();
};
Let the child default constructor call the default parent constructor, and create another child constructor with parameters to call the corresponding one of the parent:
#include <string>
using std::string;
class Alat
{
protected:
string ime;
int serBr;
int cena;
public:
void setIme(string i)
{
ime = i;
}
string getIme()
{
return ime;
}
void setSerBr(int sb)
{
serBr = sb;
}
int getSerBr()
{
return serBr;
}
void setCena(int c)
{
cena = c;
}
int getCena()
{
return cena;
}
Alat()
{
}
Alat(string i, int sb, int c) : ime(i), serBr(sb), cena(c)
{
}
~Alat()
{
}
};
class Rucni : public Alat
{
protected:
int minGodKor;
public:
Rucni() // implicit call of the parent default constructor
{
}
Rucni(string i, int sb, int c) : Alat(i, sb, c) // explicit call of the corresponding parent constructor
{
}
int getminGodKor()
{
return minGodKor;
}
void setminGodKor(int min)
{
minGodKor = min;
}
~Rucni()
{
}
};
int main()
{
Rucni r;
return 0;
}

how to do function pointer like in C++, but for variable

sorry for the title, it's quite confusing to explain, but it will be more clear with example
In C, I used to write program like this :
void createClassA()
{
}
void createClassB()
{
}
typedef struct {
const char *name;
void (*create_class)();
} MapList;
MapList mapList[] = {
{"A", &createClassA},
{"B", &createClassB },
};
void create(const char *name)
{
int i=0;
for (i=0; i < sizeof(mapList) / sizeof(MapList); i++) {
if (strcmp(name, mapList[i].name) == 0) mapList[i].create_class();
}
}
int main(int argc, char** argv)
{
if (argc < 1) return -1;
create(argv[1]);
return 0;
}
So if I have more types, all I have to do is to create the function itself and add it to the mapList.
but in C++, the best I can do is something like:
#include <iostream>
class myA{};
class myB{};
class myC{};
class Base
{
public:
template<class T>
void createClass()
{
T* t = new T();
//t->doSomethingUseful();
}
void create(const std::string name)
{
if (name=="A") createClass<myA>();
else if (name=="B") createClass<myB>();
else if (name=="C") createClass<myC>();
}
};
int main(int agrc, char** argv)
{
if (argc<1) return -1;
Base b;
b.create(argv[0]);
return 0;
}
Can I create something like :
typedef struct {
std::string name;
[CLASS_TYPE] class_type; <== I don't know how
} MapList;
so I can create a mapping List but fill it with class Type, something like
mapList[] = {
{"A", myA},
{"B", myB},
{"B", myC},
};
and then I can create iteration like:
for (int i=0; i<sizeof(mapList) / sizeof(MapList); i++) {
if (mapList[i].name == name) b.createClass<mapList[i].classType>();
}
Thanks guys :)
In C++ you can use std::function in the <functional> standard header. Specifically, your example for the map list can be written as (with lambdas):
std::map<std::string, std::function<void()>> mapList;
mapList["A"] = []() { /* ... */ };
mapList["B"] = []() { /* ... */ };
or just (without lambdas):
void createClassA() {}
void createClassB() {}
std::map<std::string, std::function<void()>> mapList;
mapList["A"] = createClassA;
mapList["B"] = createClassB;
In C++ you could do that with virtual functions:
struct ClassMaker {
virtual void create_class() = 0;
};
struct ClassMakerA : public ClassMaker {
virtual void create_class() {
...
}
};
struct ClassMakerB : public ClassMaker {
virtual void create_class() {
...
}
};
Now you can create a std::map<std::string,ClassMaker*> with your "factories", like this:
ClassMakerA makerA;
ClassMakerB makerB;
// This syntax requires C++11
std::map<std::string,ClassMaker*> makers = {
{"A", &makerA}
, {"B", &makerB}
};
Finally, you can now call create_class() based on a std::string value, like this:
void create(const std::string &name) {
ClassMaker *maker = makers[name];
if (maker) maker -> create_class();
}
You could look for Boost::any, which provides "a variant value type".
You can use derived classes and object factory, something like that would work. You can improve it by make create method to return smart pointers and make A and B constructors private to avoid creating objects on the stack.
class Base
{
static Base* create(const char *name);
};
class A : public Base
{
};
class B : public Base
{
};
Base* Base::create(const char *name)
{
if(strcmp(name,"A")==0)
return new A();
if(strcmp(name,"B")==0)
return new B();
return 0;
}
int main(int agrc, char** argv)
{
if (argc<1) return -1;
Base *b = Base::create(argv[0]);
return 0;
}
It is somewhat similar to solution by #dasblinkenlight, but avoid virtual functions overhead.

Adapter pattern in C++, with non-virtual adapted methods

I want to create an adapter class in C++, but the interface that I want to adapt to has several non-virtual methods. Can I still use the regular adapter pattern?
#include <iostream>
using namespace std;
class NewInterface{
public:
int methodA(){ cout << "A\n"; }
virtual int methodB(){ cout << "B\n"; }
};
class OldInterface{
public:
int methodC(){ cout << "C\n"; }
int methodD(){ cout << "D\n"; }
};
class Old2NewAdapter: public NewInterface {
public:
Old2NewAdapter( OldInterface* a ){ adaptee = a; }
int methodA(){ return adaptee->methodC(); }
int methodB(){ return adaptee->methodD(); }
private:
OldInterface* adaptee;
};
int main( int argc, char** argv )
{
NewInterface* NI = new Old2NewAdapter( new OldInterface() );
NI->methodA();
NI->methodB();
return 0;
}
If I have this setup, the output will be "A D" instead of "C D" as it should.
So how can I adapt OldInterface to NewInterface, without rewriting NewInterface so that all methods are virtual?
Can you introduce another class? If you can then you can replace functions that use a NewInterface with an even NewerInterface:
class NewerInterface
{
public:
int methodA()
{
// preconditions
int const result = doMethodA();
// postconditions
return result;
}
int methodB()
{
// preconditions
int const result = doMethodB();
// postconditions
return result;
}
private:
virtual int doMethodA() = 0;
virtual int doMethodB() = 0;
};
class Old2NewerInterface : public NewerInterface
{
public:
explicit Old2NewerInterface(OldInterface& x) : old_(&x)
private:
virtual int doMethodA() { return old_->methodC(); }
virtual int doMethodB() { return old_->methodD(); }
private:
OldInterface* old_;
};
class New2NewerInterface : public NewerInterface
{
public:
explicit New2NewerInterface(NewInterface& x) : new_(&x)
private:
virtual int doMethodA() { return new_->methodA(); }
virtual int doMethodB() { return new_->methodB(); }
private:
NewInterface* new_;
};

How to get struct member with a string using Macros C++

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