C++: Iteratively call a member's object methods /// a table of objects - c++

I have a bunch of object classes (A, B and C in this example) which I instantiate in my application. They all inherit one and a same interface, which I call Base. I want to interate over the objects and do a call on them.
Here are the classes and the base:
class Base
{
public:
virtual CResult init() noexcept;
};
class A : public Base
{
public:
...
};
class B : public Base
{
public:
...
};
class C : public Base
{
public:
...
};
I have then an instance of A, B and C in the application, together with its init() method:
class Application
{
public:
CResult init() noexcept;
private:
A a;
B b;
C c;
};
CResult Application::init()
{
/// iterate on a, b, c and call .init()
/// add code
}
Now, I want to call the init() methods of all my objects a, b and c iteratively.
That would mean I need to define a table with a, b and c "references" (I say references, but yes it is not possible to have, say, vector of object references). Then to iterate over the table and call each member's init() method.
What is the best OOP way to achieve this? Can anyone share sample code with the table and the iteration?

The easiest way is probably this:
Base *ptrs[] = {&a, &b, &c};
for (auto ptr : ptrs)
ptr->init();
If the variables had the same type, you could shorten this to for (auto ptr : {&a, &b, &c}). But since the types are different, you have to manually spell the pointer type when creating the array.

I have implemented it using a std::vector. The following private member in the Application class definition holds the list of components:
std::vector<Base *> m_components;
The initialization of the list is currently in the constructor:
Application::Application()
{
m_components.push_back(&a);
m_components.push_back(&b);
m_components.push_back(&c);
/// add additional components as needed
}
CResult Application::init()
{
// call all components' init
for(const auto& cmp: m_components)
{
CResult rc = cmp->init();
if(rc != CResult::OK)
{
// error; report, break the initalization
}
}
// initialization passed
}
The same approach can be used for deinit, start, stop, etc methods, and make the code quite readable and maintainable.

Related

A function overload depending on enum

Sorry for the noob question, but I cannot seem to get my head around C++'s static nature. The problem: I have a class that returns an enum and depending on it I have to convert the said class using another class and return a vector. In code:
enum TYPES { TYPE_A, TYPE_B, TYPE C }
class A {
TYPES getType() {}
}
class B : public A {}
class C : public A {}
class D : public A {}
std::vector<?> convert_to_vector(const A& a) {
// depending on what enum is returned by a.getType()
// I have to convert a into B, C, or D class and return std::vector of
// an appropriate type, e.g. int for B, float for C, etc.
}
int main() {
A a;
auto v = convert_to_vector(a);
}
The simplest way would be using switch(a.getType()) but I have different return types in each case and using auto as the return type doesn't work. I have tried templates and template specification, but they don't accept the runtime variable that is return by a.getType(). I guess there must be some simple solution that I'm overlooking here, but I have run out of ideas at this point and would be grateful for any pointers.
Thanks!
You can't change the return type of a C++ function at runtime. But you can use a variant type:
std::variant<std::vector<int>, std::vector<float>> convert_to_vector(const A& a) {
if (a.getType() == TYPE_B)
return std::vector<int>();
if (a.getType() == TYPE_C)
return std::vector<float>();
throw std::logic_error("unsupported type");
}
If you don't have C++17, you can use boost::variant instead of std::variant.
I think instead of deciding the type of a vector on an enum a much better solution would be to have a parent class A which can have a vector inside it which is based on a template variable. In your classes B, C, D you can simply inherit A and specify a template type. So, when you create a new object for B, C, D you will already have a vector member for those objects. You can also have a virtual function convertToVec which you can override in the child classes depending on how you want to convert data into a vector.
template<class T>
class A {
std::vector<T> vec;
std::vector<T> GetVector() { return vec; }
virtual convertToVec() { .... }
}
class B : public A<bool> {}
class C : public A<float> {}
class D : public A<long long int> {}
int main() {
B b;
b.GetVector();
//A* b = new B();
//b->convertToVec();
}
While it's pretty hard to follow what exactly you are trying to achieve here, going to use switch-case is not a good idea, instead you'd better to leverage polymorphism. For example:
class A {
public:
virtual void convertToVector(AuxVectorConverter& aux) = 0;
};
class B {
public:
// Add here specific implementation
virtual void convertToVector(AuxVectorConverter& aux) {
aux.convertToVectorB(this);
}
};
class C {
public:
// Add here specific implementation
virtual void convertToVector(AuxVectorConverter& aux) {
aux.doSomethingC(this);
}
};
// Aux class
class AuxVectorConverter {
public:
convertToVector(A* a) {
a->convertToVector(this);
}
convertToVectorB(B* b) {
// Do code specific for B
}
convertToVectorC(C* c) {
// Do code specific for B
}
}
int main() {
AuxVectorConverter* aux;
A* a = ...; // Initialize here either with instance of B or C
// Now, based on run time aux class will issue appropriate method.
aux.convertToVector(a);
}
You might find more details here
UPDATE (Based on comment)
An alternative approach could be to define a map from TYPES to some abstract class which will align with the patter from above, e.g.:
// Map has to be initialized with proper implementation
// of action according to type
map<Types, AbstracatAction> actions;
// Latter in the code you can do:
aux.convertToVector(actions[a->getType()]);
And action will be defined pretty similar to hierarchy I've showed above, e.g.
class AbstractAction {
public:
virtual void convertToVector(AuxVectorConverter& aux) = 0;
};
class ActionB: public AbstractAction {
public:
virtual void convertToVector(AuxVectorConverter& aux) {
aux.covertToVectorB(this);
}
};

using smart pointers in a derived class constructor

The question, at the outset: (preface: new to c++ oop programming)
How do I construct a derived class, Widget, such that I have a vector of (shared?) pointers in terms the base class, where the original objects (such that they are still of the derived class) can be accessed upon casting and dereferencing the pointers?
Say I have a base class:
class Component {
public:
int a;
int b;
virtual void rtti(){}; // for run time type information.
explicit Component(int a, int b) { this->a = a; this->b = b;}
}
And two derived classes,
class AComponent:public Component{
public:
using Component::Component;
AComponent(int a, int b) : Component(int a, int b){}
}
class BComponent:public Component{
public:
using Component::Component;
BComponent(int a, int b) : Component(int a, int b){}
}
Further, I have a Multi-Component (still generic here):
typedef shared_ptr<AComponent> AComponentPtr;
typedef shared_ptr<BComponent> BComponentPtr;
class MultiComponent{
public:
vector<AComponentPtr> A_components;
vector<BComponentPtr> B_components;
explicit MultiComponent(vector<AComponentPtr> As, vector<BComponentPtr> Bs){
this->A_components = As;
this->B_components = Bs;
}
}
Finally, I have a specific use case of this component hierarchy:
class WidgetComponentA:public AComponent{...}
class WidgetComponentB:public BComponent{...}
class Widget:public MultiComponent{
public:
using MultiComponent::MultiComponent;
Widget(WidgetComponentA a, WidgetComponentB b, WidgetComponentB c)
: MultiComponent(???){
}
}
Currently, I have the MultiComponent class constructor within Widget set up as follows:
class Widget:public MultiComponent{
public:
using MultiComponent::MultiComponent;
Widget(WidgetComponentA a, WidgetComponentB b, WidgetComponentB c)
: MultiComponent({(AComponentPtr)&a},{(BComponentPtr)&b, (BComponentPtr)&c}){}
}
Because this yields no errors on compilation.
Then, I construct the widget in my main method like so:
main(){
WidgetComponentA a = WidgetComponentA(1,2);
WidgetComponentB b = WidgetComponentB(3,4);
WidgetComponentB c = WidgetComponentB(5,6);
// now, the widget:
Widget widget = Widget(a,b,c);
// however, the pointers within the widget
// do not access valid addresses in memory.
return 0;}
The shared pointers within the Widget widget object do not reference any valid locations in memory, and fail with,
Attempt to take address of value not located in memory.
Ultimately, what I am trying to do is have Widget just hold on to the list of components of various derived types in the form of the base class shared pointers.
Then, I run generic, template functions on the class, and only cast the pointers to the widget-specific derived class pointers in functions specific to widgets.
I am using shared pointers to be safe, because I ran into the memory leak warnings...but if there is a simpler solution...
As I suggested in the comments, perhaps a polymorphic approach would be easier...
class MultiComponent{
public:
typedef std::vector<std::shared_ptr<Component>> components_vec;
components_vec components;
MultiComponent(components_vec& cv){
components = cv;
}
}
class Widget: public MultiComponent {
public:
Widget(MultiComponent::components_vec& cv)
: MultiComponent(cv){}
}
You can cast pointers to descendants of Component to Component*'s and then store them together.
Then, perhaps define a virtual void Component::display() = 0 to force the inheritors to define some sort of behaviour to your needs.
Perhaps I misunderstand what you ask but if you want to deal with objects of shared ownership then you have to make them such:
main()
{
auto a = std::make_shared<WidgetComponentA>(1,2);
auto b = std::make_shared<WidgetComponentB>(3,4);
auto c = std::make_shared<WidgetComponentB>(5,6);
// now, pass the shared stuff to widget:
Widget widget = Widget(a,b,c); // make sure that Widget has
// such constructor that accepts
// the shared pointers
return 0;
}

Grouping two types together

I use a third party library over which I have no control. It contains 2 classes A and B, which both define a method with the same name:
class A {
public:
...
void my_method ();
};
class B {
public:
...
void my_method ();
};
I want to create a class C that contains a member which is of class A or B. Crucially, I can know only at runtime whether I will need A or B. This class C will only call the method my_method.
If I could modify the code, I would simply make A and B derive from a parent class (interface) that defined my_method. But I can't.
What is the simplest/most elegant way to create this class C? I could of course define C in this way:
class C {
public:
void call_my_method() { if (a) a->my_method() else b->my_method(); }
private:
A* a;
B* b;
But I want to avoid paying the cost of the if statement everytime. It also feels inelegant. Is there a way I can create a super type of class A or B? Or any other solution to this problem?
You may use std::function (not sure it has better performance though), something like:
class C {
public:
void call_my_method() { my_method(); }
void use_a(A* a) { my_method = [=]() { a->my_method() }; }
void use_b(B* b) { my_method = [=]() { b->my_method() }; }
private:
std::function<void()> my_method;
};
No; at some point you need branching. The best you can do is to hoist the branching up/down the call stack†, so that more of your program is encapsulated within the figurative if/else construct and the branch itself need be performed less frequently. Of course then you need to duplicate more of your program's source code, which is not ideal.
The only improvement I'd suggest at this time is a construct such as boost::variant. It basically does what you're already doing, but takes up less memory and doesn't have that layer of indirection (using what's called a tagged union instead). It still needs to branch on access, but until profiling has revealed that this is a big bottleneck (and you'll probably find that branch prediction alleviates much of this risk) I wouldn't go any further with your changes.&ddagger;
† I can never remember which way it goes lol
&ddagger; One such change might be to conditionally initialise a function pointer (or modern std::function), then call the function each time. However, that's a lot of indirection. You should profile, but I'd expect it to be slower and harder on the caches. An OO purist might recommend a polymorphic inheritance tree and virtual dispatch, but that's not going to be of any use to you once you care about performance this much.
How about using inheritance with a virtual function, using a 'base class' (C):
class C
{
public:
virtual void do_method() = 0;
};
class D : public C, private A
{
void do_method() { my_method(); }
};
class E : public C, private B
{
void do_method() { my_method(); }
}
Then this will work:
C * d = new D();
d->do_method();
Suggest to wrap your A and B objects into some helper template TProxy which realizes IProxy interface. Class C (or Consumer) will work with IProxy interface and won't know about type of the object inside Proxy
#include <stdio.h>
struct A {
void func () { printf("A::func\n"); }
};
struct B {
void func () { printf("B::func\n"); }
};
struct IProxy
{
virtual void doFunc() = 0;
virtual ~IProxy() {};
};
template<typename T>
struct TProxy : public IProxy
{
TProxy(T& i_obj) : m_obj(i_obj) { }
virtual void doFunc() override { m_obj.func(); }
private:
T& m_obj;
};
class Consumer
{
public:
Consumer(IProxy& i_proxy) : m_proxy(i_proxy) {}
void Func() { m_proxy.doFunc();}
private:
IProxy& m_proxy;
};
Main:
int main()
{
A a;
TProxy<A> aProxy(a);
B b;
TProxy<B> bProxy(b);
Consumer consumerA{aProxy};
consumerA.Func();
Consumer consumerB{bProxy};
consumerB.Func();
return 0;
}
Output:
A::func
B::func

Passing object into array that are of the same parent class

As I am still somewhat new to programming in C++ I was just curious if it were possible to pass objects pointers to an array in order for code consolidation.
Header file like such;
class.h
class parent
{
some information.....
};
class child1 : public parent
{
some information.....
};
class child2 : public parent
{
some information.....
};
Main file like such;
main.cpp
#include "class.h"
int main()
{
child1 instanceChild1;
child2 instanceChild2;
child1* pointer1 = &instanceChild1;
child2* pointer2 = &instanceChild2;
parent array[2] = {pointer1 , pointer2};
}
I am trying to achieve such so that I may create a function that uses a dynamic array in order to hold object pointers so that I may dereference them in the function and manipulate them accordingly. Though I am having issues getting the different pointers to work together when going into an array. I need such functionality since there will be many different objects(all under the same parent) going in and out of this function.
Yes it is possible.
But you need to declare the array like this
parent * arr[] = { ... }
or it would be better if you use a vector
vector<parent *> arr;
arr.push_back(childPointer);//For inserting elements
as #pstrjds and #basile has written
and if you want to use child specific member functions, you can use dynamic cast
ChildType1* ptr = dynamic_cast<ChildType1*>(arr.pop());
if(ptr != 0) {
// Casting was succesfull !!! now you can use child specific methods
ptr->doSomething();
}
else //try casting to another child class
** your compiler should support RTTI in order for this to work correctly
you can see this answer for details
I prefer to use pure Virtual functions like this
class A {
public :
enum TYPES{ one , two ,three };
virtual int getType() = 0;
};
class B : public A{
public:
int getType()
{
return two;
}
};
class C : public A
{
public:
int getType()
{
return three;
}
};

One pointer, two different classes in c++

Suppose I have two structures a and b, each hold several variable in them (most of the variable are c++ core types but not all).
Is there a way to create a a pointer named c that can point to either one of them? Alternatively, is there a way to create a set that can hold either one of them?
Thanks
The usual way to create a pointer that can point to either of the two is to make them inherit from a common base-class. Any pointer of the base-class can point to any sub-class. Note that this way you can only access elements that are part of the base-class through that pointer:
class Base {
public:
int a;
};
class Sub1 : public Base {
public:
int b;
};
class Sub2 : public Base {
public:
int c;
};
int main() {
Base* p = new Sub1;
p.a = 1; // legal
p.b = 1; // illegal, cannot access members of sub-class
p = new Sub2; // can point to any subclass
}
What you are trying to achieve is called polymorphism, and it is one of the fundamental concepts of object oriented programming. One way to access member of the subclass is to downcast the pointer. When you do this, you have to make sure that you cast it to the correct type:
static_cast<Sub1*>(p).b = 1; // legal, p actually points to a Sub1
static_cast<Sub2*>(p).c = 1; // illegal, p actually points to a Sub1
As for your second question, using the technique described above, you can create a set of pointers to a base-class which can then hold instance of any of the subclasses (these can also be mixed):
std::set<Base*> base_set;
base_set.insert(new Sub1);
base_set.insert(new Sub2);
Alternatively, is there a way to create a set that can hold either one
of them?
Take a look at Boost.Any and Boost.Variant. If you have just 2 classes, then variant should suffice. If you plan other types, and don't want to recompile this 'set', then use any.
Then use any container of either any or variant.
#include <boost/any.hpp>
#include <boost/variant.hpp>
#include <vector>
class A { };
class B { };
class C { };
int main()
{
// any
std::vector<boost::any> anies;
anies.push_back(A());
anies.push_back(B());
A a0 = boost::any_cast<A>(anies[0]);
A b0 = boost::any_cast<A>(anies[1]); // throws boost::bad_any_cast
// variant
std::vector<boost::variant<A,B> > vars;
vars.push_back(A());
vars.push_back(B());
A a1 = boost::get<A>(vars[0]);
A b1 = boost::get<A>(vars[1]); // throws boost::bad_get
// and here is the main difference:
anies.push_back(C()); // OK
vars.push_back(C()); // compile error
}
Edit: having more than 2 classes is of course possible for variant, too. But extending variant so it is able to hold a new unanticipated type without recompilation is not.
If a and b are unrelated, then you can use a void* or, better, a boost any type.
If a is superclass of b, you can use an a* instead.
If they both inherit from the same type you can do it. Thats how OOP frameworks work, having all classes inherit from Object.
Although you can do that, what would that pointer mean? If any portion of your application gets hold on the pointer to 'either a or b', it cannot do a lot with it, unless you provide extra type information.
Providing extra type information will result in client code like
if( p->type == 'a' ) {
... a-specific stuff
} else if( p->type == 'b' ) {
... b-specific stuff
} ...
Which isn't very useful.
It would be better to delegate 'type-specificness' to the object itself, which is the nature of object-oriented design, and C++ has a very good type-system for that.
class Interface {
public:
virtual void doClientStuff() = 0; //
virtual ~theInterface(){};
};
class A : public Interface {
virtual void doClientStuff(){ ... a-specific stuff }
};
class B : public Interface {
virtual void doClientStuff(){ ... b-specific stuff }
};
And then your client code will become more type-unaware, since the type-switching is done by C++ for you.
void clientCode( Interface* anObject ) {
anObject->doClientStuff();
}
Interface* i = new A();
Interface* j = new B();
clientCode( i );
clientCOde( j );
There are several ways to do this:
Using the more generic base type, if there is an inheritance relationship.
Using void* and explicitly casting where appropriate.
Creating a wrapper class with the inheritance relationship needed for #1.
Using a discriminating container via union.
Since others have already described the first three options, I will describe the fourth. Basically, a discriminated container uses a union type to use the storage of a single object for storing one of multiple different values. Typically such a union is stored in a struct along with an enum or integral type for distinguishing which value is currently held in the union type. As an example:
// Declarations ...
class FirstType;
class SecondType;
union PointerToFirstOrSecond {
FirstType* firstptr;
SecondType* secondptr;
};
enum FIRST_OR_SECOND_TYPE {
FIRST_TYPE,
SECOND_TYPE
};
struct PointerToFirstOrSecondContainer {
PointerToFirstOrSecond pointer;
FIRST_OR_SECOND_TYPE which;
};
// Example usage...
void OperateOnPointer(PointerToFirstOrSecondContainer container) {
if (container.which == FIRST_TYPE) {
DoSomethingWith(container.pointer.firstptr);
} else {
DoSomethingElseWith(container.pointer.secondptr);
}
}
Note that in the code below, "firstptr" and "secondptr" are actually two different views of the same variable (i.e. the same memory location), because unions share space for their content.
Note that even though this is a possible solution, I seriously wouldn't recommend it. This kind of thing isn't very maintainable. I strongly recommend using inheritance for this if at all possible.
Just define a common superclass C and two subclasses A, B of C. If A and B have no common structure (no common attributes), you can leave C empty.
The define:
A *a = new A();
B *b = new B();
C *c;
Then you can do both
c = a;
or
c = b;
Abstract Class !!!! -- simple solutions
To have a base class that can be used as a pointer to several derived sub classes. (no casting needed)
Abstract class is define when you utilize a virtual method in it. Then you implement this method in the sub-class... simple:
// abstract base class
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
};
class Rectangle: public Polygon {
public:
int area (void)
{ return (width * height); }
};
class Triangle: public Polygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
Polygon * ppoly1 = new Rectangle (4,5);
Polygon * ppoly2 = new Triangle (4,5);
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << '\n';
cout << ppoly2->area() << '\n';
return 0;
}