Class interaction tips - c++

I am puzzled by some issues when trying to design interacting classes.
If a class A needs some data from class B, either in the form of a pointer or standard container format, (or even lets become more ambitious and say in the form of some shared_ptr members to stl containers.), my way is to use a function that returns the same kind of arguments and design class B methods with conforming arguments? Are there a general rules of thumb for designing interacting classes and share data between these classes?
Could you please draw a general scheme for some common situations that are generally encountered in practice(and along some examples are appreciated)? I guess I should read some examples on class interaction in C++, any pointers on this are also appreciated?
A small sample could be:
#include <iostream>
#include <vector>
#include <iterator>
#include <cassert>
using namespace std;
class A{
public:
A(int s, int val):sz(s), val(val), v(new vector<int>){}
int fill_vector(){
for(int k=0;k!=sz;++k)
v->push_back(val);
return 0;
}
~A(){
cout << "Dtor is deleting the pointer to vector\n";
delete v;
}
vector<int>* get_pointer_to_vector_in_A(){ return v; }
private:
int sz, val;
vector<int> *v;
};
class B{
public:
B(){} // does nothing basically
int print_vector_contents_from_A( vector<int> *v_from_A ) const
{
assert(!v_from_A->empty());
copy(v_from_A->begin(), v_from_A->end(),
ostream_iterator<int>(cout, "\n") );
}
};
int main()
{
A a(10, 4);
a.fill_vector();
B b;
b.print_vector_contents_from_A( a.get_pointer_to_vector_in_A() );
return 0;
}

It rather depends on what A is, conceptually. If A can be validly viewed as a sequence of int, then I'd implement size_t size() const and int &operator[](size_t) (+ its const counterpart) on it. These can just delegate their activities to v.size and v[] or v.at.
In B, you can then define
static void B::print_contents(A const &a)
{
for (size_t i=0; i < a.size(); i++)
std::cout << a[i] << '\n';
}
A member that returns an std::vector<int>* breaks encapsulation: you can never change the implementation of A away from std::vector<int> except with very ugly hacks to ensure get_pointer_to_vector_in_A still works with the same semantics.

One great one-directional way to do this is:
class A {
public:
void fill_vector();
int vec_size() const { return vec.size(); }
int get_data(int i) const { return vec[i]; }
};
class B {
public:
B(A &a) : a(a) { }
void init() { a.fill_vector(); }
void fetch_and_print()
{ for(int i=0;i<a.vec_size();i++) std::cout << a.get_data(i); }
private:
A &a;
};
int main() {
A a;
B b(a);
b.init();
b.fetch_and_print();
}
The constructor parameter for class B is the important bit.

Related

Is there a way to set the function pointer according to user parameter?

I have one version of code with benchmark surround with macros to enable or disable, and I want to change the code that I can turn on and off the benchmark settings without recompiling my code and without a lot of if-else or without code duplication (version with the benchmark and a version without)?
A way to set the vtable for the correct functions?
EDIT: added code sample for what I don't wont to do
EDIT V2 I understood from the answers that there isn't a way, so if I create two shared object can I code on run time to which one to link to?
#include <iostream>
#include <string>
using namespace std;
struct A
{
virtual int add(int a,int b)=0;
};
struct B:public A
{
virtual int add(int a,int b){return a+b;}
};
struct C:public A
{
virtual int add(int a,int b)
{
cout << "time" << endl;
return a+b;
}
};
int main(int argc,char* argv[])
{
A* a;
string s(argv[1]);
if(s.compare("t"))
{
a = new C;
}
else
{
a=new B;
}
cout << a->add(2,5);
return 0;
}
A way to set the vtable for the correct functions?
Vtable is an implementation detail. The way this detail is normally implemented is that the vtable pointer is set by the constructor.
You can have one interface and a factory function pointer that you set once and use many times (also known as Factory design pattern). E.g.:
#include <memory>
struct A {
virtual void f() = 0;
virtual ~A() noexcept = default;
};
std::unique_ptr<A>(*factory)(); // Factory function.
struct A1 : A {
void f() override;
};
struct A2 : A {
void f() override;
};
int main(int ac, char** av) {
if(ac >= 1 && **av == 'd')
factory = []() { return std::unique_ptr<A>(new A2); };
else
factory = []() { return std::unique_ptr<A>(new A1); };
auto a = factory();
}
You are almost there. With the decorator pattern, you avoid code duplication.
For the abstract class A a decorator printing the time would look like this:
struct TimedA : public A
{
TimedA(A* base) : base_(base) {}
virtual int add(int a,int b)
{
cout << "time" << endl;
return base_->add(a, b);
}
A* base_;
};
The point of the decorator is that you can append it to any object of type A and it will inject the additional behavior.

Compiler warning for mixed array and polymorphism

In More Effective C++, an interesting point brought up is that mixing array's and polymorphism is a bad idea. For eg:
class Base {
public:
Base(int y) : a(y) {}
int a;
};
class D : public Base {
public:
D(int w, int y) : Base(y), c(w) {}
int c;
};
std::ostream& operator<<(std::ostream& os, const Base &obj )
{
os << obj.a << std::endl;
return os;
}
// This function will work perfectly well if i pass in a `Base` array,
// but if i pass in `D` array we are going to run into some problems.
// Namely that `arr[i+1] = &arr[i] + sizeof(Base)` will not progress
// the array correctly for a `D` array.
void printArray(const Base arr[]) {
for (int i = 0; i < 5; ++i) {
std::cout << arr[i];
}
}
int main() {
D arr[5] = { D(0, 10), D(1, 11), D(2, 12), D(3, 13), D(4, 14)};
printArray(arr); // This compiles without complaint! I understand that the
// conversion is legal, but it seems like a warning
// about this would be a good idea.
}
Note: I know this is bad design but is to illustrate a point.
The problem here is that when mixing these two in the way i have above, when we iterate through the array to print we will not progress the element of the array by the correct amount (ie we move by sizeof(Base) instead of sizeof(D)). This results in the output:
10
0
11
1
12
[Live example.]
(And i am guessing that calling the operator<< like this is probably UB).
When compiling with g++ -std=c++1y -Wall -Weffc++ -pedantic main.cpp I get no warnings or errors.
Is there a compiler flag that I can enable that indicates a warning in this scenario?
If not, why not?
A compiler could do a lot of static analyzing, and could know that the pointer arr in the function is used as an array with unexpected results.
However, doing that is slow and uses a lot (more) of memory, and programmers are generally impatient and want their compilations to be done as quick as possible using as little other resources as possible too. Therefore most compilers only do static analyzes that are relatively quick and easy, leaving the hard work to dedicated static analyzers.
void printArray(const Base arr[]) is equivalent to void printArray(const Base* arr).
It's legal to pass a pointer of type D to a function whose parameter is of type const Base*. So the compiler won't give any warnings.
FYI, mixing arrays and polymorphism can be done if the polymorphism is provided as an implementation detail of a handle class:
#include <iostream>
#include <vector>
// a handle which will happily own any class which implements the concept
struct Thing
{
struct concept
{
virtual void sayHello() const = 0;
virtual ~concept() = default;
};
Thing(std::unique_ptr<concept> ptr) : _impl(std::move(ptr)) {}
void sayHello() const { _impl->sayHello(); }
std::unique_ptr<concept> _impl;
};
struct thing_a : Thing::concept
{
void sayHello() const override { std::cout << "hello from A\n"; }
};
struct thing_b : Thing::concept
{
void sayHello() const override { std::cout << "hello from B\n"; }
};
int main()
{
std::vector<Thing> things;
things.emplace_back(std::make_unique<thing_a>());
things.emplace_back(std::make_unique<thing_b>());
for (const auto& t : things) { t.sayHello(); }
}
expected output:
hello from A
hello from B

C++ inheritance, calling the given classes function instead of its parent?

Really bad title, couldn't think of how to word it, sorry.
So say I had the following code:
class A {
virtual int getSize() {
return 0;
}
}
class B : public A {
int getSize() {
return 32;
}
}
void doStuff(A a) {
std::cout << a.getSize() << std::endl;
}
int main() {
B b;
doStuff(b);
}
It would print out 0, however I want it to print out 32. In other words, I want to pass it the class and it prints out that classes function, so I could create a class C, where the size is 64, and if I pass that C instance to the doStuff function, I want it to print 64.
Is there any way I can do this in C++, would I have to use templates or some fancy C++ feature I don't know about?
A one-byte patch:
void doStuff(A &a) {
std::cout << a.getSize() << std::endl;
}
Your version takes the argument by value, which means that the function makes a copy of b (a copy which is an A) and then calls the copy's getSize(). In this version, the function takes the argument by reference, and calls b's own getSize(), which is B::getSize().
You should use pointers, or even better: smart pointers! That way, the function of the runtime type gets called. It's a basic example of polymorhpism. If you want to avoid pointers, Beta's slicing approach is equally valid.
#include <iostream>
#include <memory>
class A {
virtual int getSize() {
return 0;
}
}
class B : public A {
virtual int getSize() {
return 32;
}
}
void doStuff(std::shared_ptr<A> a) {
std::cout << a->getSize() << std::endl;
}
int main() {
std::shared_ptr<A> b(new B());
doStuff(b); // Will output '32'.
}
This should correctly call the function as implemented by B.
Slicing the object is one approach, and in addition I think you're asking for, I think, a pretty straightforward use of polymorphism in C++. http://www.cplusplus.com/doc/tutorial/polymorphism/
That's almost immediately applicable, just call your class A Shape, and B and C could be Square and Triangle. Your DoStuff function could take a pointer to a Shape, then you can pass it a triangle or a square, and when you deference the Shape in the function, it will call the correct function.
So you'd have (also you need to make the members public, I think):
class A {
public:
virtual int getSize() {
return 0;
}
};
class B : public A {
public:
int getSize() {
return 32;
}
};
void doStuff(A* a) {
std::cout << a->getSize() << std::endl;
}
int main() {
B b;
doStuff(&b);
}

C++ Referencing inside a polymorphic object

I have two classes
class A { C* c; }
class B { D* d; }
and find I need to construct a std::vector whose elements are either A or B (with the sequence decided at run time. So I constructed a polymorphic
class Poly {
int oType;
void* oPtr;
}
as well as constructor
Poly::Poly(int type)
{
if (type == 1) oPtr = new (A*) oPtr();
if (type == 2) oPtr = new (B*) oPtr();
oType = type;
}
along with a similarly structured destructor. Now
std::vector<Poly*> test;
works. However, I am having trouble accessing the subobjects.
I tried
if (test->oType == 1) test->oPtr->a;
if (test->oType == 1) test->(A*)oPtr->a;
if (test->oType == 1) (A*)(test->oPtr)->a;
all giving me the compiler error:
'void*' is not a pointer-to-object type
How do I convince the compiler that it's OK to reference a, if I know that the type of oPtr is A*?
How do I convince the compiler that it's OK to reference a, if I know
that the type of oPtr is A*?
Strictly I think the answer to that is: ((A*)(test->oPtr))->a. The better way to do that in C++ uses the cast operator: static_cast<A*>(test->oPtr)->a
HOWEVER This is not typically how this problem is addressed in c++. So I have provided a more usual approach that you may find useful:
class Poly
{
public:
virtual ~Poly() {}
virtual void do_something() = 0; // each sub-type has its own version of this
};
class A: public Poly
{
public:
void do_something() /* override */ // c++11 only
{
std::cout << "Doing something A specific\n";
}
};
class B: public Poly
{
public:
void do_something() /* override */ // c++11 only
{
std::cout << "Doing something B specific\n";
}
};
int main()
{
std::vector<Poly*> polys;
// create data structure
polys.push_back(new A);
polys.push_back(new A);
polys.push_back(new B);
polys.push_back(new A);
// use objects polymorphically
for(size_t i = 0; i < polys.size(); ++i)
polys[i]->do_something();
// clean up memory (consider using 'smart pointers')
for(size_t i = 0; i < polys.size(); ++i)
delete polys[i];
}
As others mentioned, the polymorphic way is to use virtual functions.
Here is an implementation using smart pointers. The creator class is responsible for creating the Poly object we are asking for. This isolates the creation to one class.
Note that there are more sophisticated ways of doing this. The goal here is to show, more or less, how it would be done using C++.
#include <vector>
#include <memory>
#include <iostream>
class Poly
{
public:
virtual void Test() = 0;
};
typedef std::unique_ptr<Poly> PolyPtr;
class A : public Poly
{
public:
void Test() { std::cout << "Test for A" << "\n"; }
};
class B : public Poly
{
public:
void Test() { std::cout << "Test for B" << "\n"; }
};
class PolyCreator
{
public:
PolyPtr CreatePolyObject(int oType)
{
switch( oType )
{
case 1:
return PolyPtr(new A());
case 2:
return PolyPtr(new B());
}
throw "Could not find type in list";
}
};
int main()
{
PolyCreator pCreator;
std::vector<PolyPtr> PolyPtrVect;
// create objects
PolyPtrVect.push_back(pCreator.CreatePolyObject(1));
PolyPtrVect.push_back(pCreator.CreatePolyObject(2));
// call Test functions for each
std::vector<PolyPtr>::iterator it = PolyPtrVect.begin();
while ( it != PolyPtrVect.end())
{
(*it)->Test();
++it;
}
}
Output:
Test for A
Test for B
Note
There is only one if() statement that is isolated to the PolyCreator class.
There are no memory leaks due to usage of std::unique_ptr.
Poly is an abstract class. All derived classes must implement the Test function.

using function object though function pointer is required

I have to use some legacy code expecting a function pointer, let's say:
void LEGACY_CODE(int(*)(int))
{
//...
}
However the functionality I have is within a functor:
struct X
{
Y member;
X(Y y) : member(y)
{}
int operator()(int)
{
//...
}
};
How should I modify/wrap class X so that LEGACY_CODE can access the functionality within X::operator()(int) ?
Your question makes no sense. Whose operator do you want to call?
X a, b, c;
LEGACY_CODE(???); // what -- a(), b(), or c()?
So, in short, you cannot. The member function X::operator() is not a property of the class alone, but rather it is tied to an object instance of type X.
Search this site for "member function" and "callback" to get an idea of the spectrum of possible approaches for related problems.
The crudest, and quite possibly not-safe-for-use, workaround to providing a free function would go like this:
X * current_X; // ugh, a global
int dispatch(int n) { current_X->operator()(n); }
int main()
{
X a;
current_X = &a;
LEGACY_CODE(dispatch);
}
You can see where this is going...
A simple wrapper function looks like:
int wrapperfunction(int i) {
Functor f(params);
return f(i);
}
If you want to be able to pass the parameters to the functor itself, the simplest way is to sneak them in using (brr) a global variable:
Functor functorForWrapperfunction;
int wrapperfunction(int i) {
functorForWrapperfunction(i);
}
// ...
void clientCode() {
functorForWrapperfunction = Functor(a,b,c);
legacyCode(wrapperfunction);
}
You can wrap it with a class with a static method and a static member if you want.
Here's one compile-time solution. Depending on what you need, this might be a too limited solution for you.
template<typename Func, int Param>
int wrapper(int i)
{
static Func f(Param);
return f(i);
}
A thread-safe version under the restriction that the legacy code is not called with different parameters in a thread.
IMHO, one cannot get rid of global storage.
#include <boost/thread.hpp>
#include <boost/thread/tss.hpp>
class AA
{
public:
AA (int i) : i_(i) {}
void operator()(int j) const {
static boost::mutex m; // do not garble output
boost::mutex::scoped_lock lock(m);
std::cout << " got " << j << " on thread " << i_ << std::endl;
Sleep(200); }
int i_;
};
// LEGACY
void legacy_code(void (*f)(int), int i) { (*f)(i); }
// needs some global storage through
boost::thread_specific_ptr<AA> global_ptr;
void func_of_thread(int j)
{
AA *a = global_ptr.get();
a->operator()(j);
}
void worker(int i)
{
global_ptr.reset(new AA(i));
for (int j=0; j<10; j++)
legacy_code(func_of_thread,j);
}
int main()
{
boost::thread worker1(worker,1) , worker2(worker,2);
worker1.join(); worker2.join();
return 0;
}