I'm working with some code where I have the following setup.
struct data
{
void change_safe_member(){}
void read_data(){}
void change_unsafe_member(){}
};
struct data_processor
{
std::shared_ptr<data> get_data(){}
void return_data(std::shared_ptr<data> my_data)
{
my_data->change_unsafe_member(); // ONLY data_processor should call this function.
}
};
struct client
{
void foo(std::shared_ptr<data_processor>& my_processor)
{
auto my_data = my_processor->get_data();
my_data->change_safe_member();
//my_data->change_unsafe_member(); SHOULD NOT BE POSSIBLE TO CALL
my_processor->return_data(my_data);
}
};
The change_unsafe_member should only be used internally by the processor so I would like to hide it or disable it for the client. But I don't know of any nice ways of doing this without resorting to ugly casts...
struct internal_data
{
void change_unsafe_member(){}
};
struct data : public internal_data
{
void change_safe_member(){}
void read_data(){}
};
struct data_processor
{
std::shared_ptr<data> get_data(){}
void return_data(std::shared_ptr<data> my_data)
{
auto internal_data = std::static_pointer_cast<internal_data>(my_data);
internal_data->change_unsafe_member();
}
};
Anyone know of a good pattern to use in situations like this? Maybe visitor pattern or something similar?
EDIT:
As pointed out in the comments one could declare friend classes, there is however one problem... the following will not work.
struct data
{
void change_safe_member(){}
void read_data(){}
private:
friend class data_processor;
virtual void change_unsafe_member(){}
};
struct data_decorator : public data
{
data_decorator(const std::shared_ptr<data>& decoratee) : decoratee_(decoratee){}
void change_safe_member(){decoratee_->change_safe_member();}
void read_data(){decoratee_->read_data();}
private:
virtual void change_unsafe_member()
{
std::cout << "Hello!"; // Add functionality
decoratee_->change_unsafe_member(); // Won't work... compiler error
}
std::shared_ptr<data> decoratee_;
};
// Another example
struct data_group_decorator : public data
{
data_group_decorator (const std::vector<std::shared_ptr<data>>& decoratees) : decoratees_(decoratees){}
void change_safe_member(){decoratee_->change_safe_member();}
void read_data(){decoratee_->read_data();}
private:
virtual void change_unsafe_member()
{
for(size_t n = 0; n < decoratees_.size(); ++n)
decoratees_[n]->change_unsafe_member(); // Won't work... compiler error
}
std::vector<std::shared_ptr<data>> decoratees_;;
};
You can make this happen with inheritance.
struct Y;
struct X {
friend struct Y;
private:
change_unsafe_member() {}
};
struct Y {
protected:
change_unsafe_member(X& x) { x.change_unsafe_member(); }
};
struct some_other : Y {
X x;
change_safe_member() { change_unsafe_member(x); }
};
Any class that inherits from Y can gain X's friendship for any functions that Y defines as effectively forwards from X.
Your last example looks like what you're really asking for is inherited friendship; i.e. you want to have a hierarchy of decorator - derived classes which are all allowed to call the private member function in data. That's answered (with "generally no") elsewhere:
Why does C++ not allow inherited friendship?
Polymorphism might provide some relief in your specific scenario, make class data_decorator an "almost pure" virtual base class, with the only nonvirtual member being a protected change_unsafe_member(), and make that in turn a friend of class data. All decorators would inherit from data_decorator, and call its protected nonvirtual member.
Related
My code structure is like below where multiple classes implement Interface. In Example class I store a pointer to the Interface and new() it in the constructor appropriately (depending on constructor parameters not shown here). I'm looking for ways to avoid using new() in this scenario but haven't got a solution yet. What's the best practice for something like this?
class Interface
{
virtual void Foo() = 0;
};
class A : public Interface
{
void Foo() { ... }
};
class B : public Interface
{
void Foo() { ... }
};
class Example
{
private:
Interface* m_bar;
public:
Example()
{
m_bar = new A(); // deleted in destructor
}
};
There are two ways this is typically done, each with their own merits.
If A is truely defined at compile time, than a typical way to handle this is to simply use a template type:
template <typename T>
class TemplateExample
{
T m_bar;
public:
TemplateExample() : m_bar() {};
}
This has some downsides. TemplateExample<A> becomes unrelated to TemplateExample<B>, the error messages when T doesn't follow the correct interface are pretty obtuse, ect. The upside is this may use duck typing rather than interface typing, and m_bar is a concrete instance.
The other (arguable more common) way is to do the following
class UniquePtrExample
{
std::unique_ptr<Interface> m_bar;
public:
UniquePtrExample() : m_bar(new A()){}
};
This has the benefit of being able to be run time configuratble if you follow a cloable pattern:
class Interface
{
public:
virtual void Foo() = 0;
virtual Interface* clone() const = 0;
};
template <typename T>
class CloneHelper : public Interface
{
public:
virtual Interface* clone() const { return new T(static_cast<const T&>(*this));}
};
class A : public CloneHelper<A>
{
virtual void Foo() { std::cout << 'A' << std::endl; }
};
class B : public CloneHelper<B>
{
virtual void Foo() { std::cout << 'B' << std::endl; }
};
class UniquePtrExample
{
std::unique_ptr<Interface> m_bar;
public:
UniquePtrExample() : m_bar(new A()){}
UniquePtrExample(const Interface& i) : m_bar(i.clone());
};
Note you can further extend the above to have a move variant of the clone function.
The following code doesn't work, as you can't static_cast from private base class.
Replacing the cast with a C-style cast works (although I originally thought this would invoke undefined behaviour apparently it does not, see this answer), but is rather ugly as it also allows you to bypass const-checking, etc. The other approach would be to make CRTPBase a friend, but that would expose all of Derived's private members.
Is there another way of writing this without using a C-style cast and without making CRTPBase a friend?
template<typename T>
struct CRTPBase {
void callBase() {
T * derived = static_cast<T*>(this);
derived->publicMethod();
}
};
struct Derived : private CRTPBase<Derived> {
void callParent() { this->callBase(); }
void publicMethod() {}
};
int main() {
Derived d;
d.callParent();
return 0;
}
I think the best solution is to avoid private inheritance and instead opt for data hiding.
Marking the member function protected will prevent access from everywhere except derived classes. A further bonus public inheritance is used instead.
template<typename T>
class CRTPBase {
protected:
void callBase() {
T * derived = static_cast<T*>(this);
derived->publicMethod();
}
};
struct Derived : public CRTPBase<Derived> {
void callParent() { this->callBase(); }
void publicMethod() {}
};
int main() {
Derived d;
d.callParent();
d.callBase() // <- illegal
return 0;
}
Not an ideal solution, but you can restrict the friendship to a unique method as follow:
template<typename T>
struct CRTPBase {
friend T; // So T can see asDerived.
void callBase() { asDerived()->publicMethod(); }
private:
T* asDerived() { return static_cast<T*>(this); }
};
struct Derived : private CRTPBase<Derived> {
friend Derived* CRTPBase<Derived>::asDerived();
void callParent() { this->callBase(); }
void publicMethod() {}
};
Please consider the following (simplified) class hierarchy and processing functions:
struct msgBase
{
virtual int msgType() const=0;
};
struct msgType1:public msgBase
{
virtual int msgType() const{return 1;}
};
struct msgType2:public msgBase
{
virtual int msgType() const {return 2;}
};
void process(const msgType1& mt1)
{
// processing for message type 1
}
void process(const msgType2& mt2)
{
// processing for message type 2
}
void process(const msgBase& mbase)
{
switch(mbase.msgType())
{
case 1:
process(static_cast<const msgType1&>(mbase));
break;
case 2:
process(static_cast<const msgType2&>(mbase));
break;
}
}
In an integrated design, msgBase would be given a virtual "process" method, to avoid needing to iterate over the types.
If it's not possible or desirable to modify any of the classes, are there any alternatives to iterating over the types?
I've experimented with a decorator/factory pattern where a parallel hierarchy of classes encapsulates the given classes, and implements the necessary virtual functions, but this results in an awful lot of boilerplate, and the factory function still needs to iterate over the types!
I could replace the switch statement with a series of dyamic_casts, but that still leaves the same weaknesses.
As requested by Simon, here is what I mean by CRTP:
typedef <class Derived>
struct msgBase
{
virtual void process(){
// redirect the call to the derived class's process()
static_cast<Derived*>(this) -> process();
};
struct msgType1:public msgBase<msgType1>
{
void process(){
// process as per type-1
}
};
struct msgType2:public msgBase<msgType1>
{
void process(){
// process as per type-2
}
};
What's happening here? Consider this case:
msgBase* msg = new msgType1();
msg->process();
normally (without CRTP) this would only call msgBase::process(). But now, msgBase "knows" about msgType1 using the template, so it is redirected to msgType1::process at compile time.
Something like this could work:
These classes are used to do the casting automatically:
struct dispatcher_base {
virtual void process(const msgBase&) = 0;
};
template <class T>
struct dispatcher_impl : dispatcher_base {
void process(const msgBase& b) override {
::process(static_cast<const T&>(b));
}
};
We'll store them in a map:
auto g_table = std::map<int, std::unique_ptr<dispatcher_base>>{};
But now you have to initialize this table somewhere:
template <class T>
void register_msg() {
g_table[T{}.msgType()].reset(new dispatcher_impl<T>{});
}
...
register_msg<msgType1>();
register_msg<msgType2>();
You can add an assert to register_msg to make sure that msgTypes are unique.
Your process function will look like this:
void process(const msgBase& b) {
assert(g_table.find(b.msgType()) != g_table.end());
g_table[b.msgType()]->process(b);
}
You can replace assert with any other logic of course.
If you can't modify the classes then you can use decorators to get polymorphic type deduction.
struct DecorBase {
DecorBase(msgBase& b) : b_(b) {}
virtual ~DecorBase() {}
virtual void process() = 0;
msgBase& b_;
};
struct DecorType1 : public DecorBase {
DecorType1(msgType1& t1) : DecorBase(t1) {}
void process() override {
std::cout << "Processing Type 1" << std::endl;
}
};
struct DecorType2 : public DecorBase {
DecorType2(msgType2& t2) : DecorBase(t2) {}
void process() override {
std::cout << "Processing Type 2" << std::endl;
}
};
And use it like this:
msgType1 t1;
msgType2 t2;
DecorType1 dt1(t1); // Wrap objects in respective decorator.
DecorType2 dt2(t2);
DecorBase& base = dt2;
base.process(); // Uses polymorphism to call function in derived type.
This will require you to write a decorator for every derived type but at least you don't have to iterate over all types during the function call.
For a container class I'd like to provide an interface with several functions which are grouped into categories, for example:
Data::Get::FirstGetter()
Data::Get::SecondGetter()
Data::Set::FirstSetter()
Data::Set::FirstSetter()
This would allow for something like this:
Data myData;
myData::Set::FirstSetter( stuff );
std::cout << myData::Get::FirstGetter() << std::endl; // -> "stuff"
Obviously the code itself is bogus and I've used the scope operator :: as a potential placeholder for something else (I am aware that you can not create namespaces within a class).
An approach to achieve something like this is demonstrated in the following snippet:
#include <iostream>
struct Foo {
private:
struct aBar {
void IFunc(){
std::cout << "IFunc()" << std::endl;
}
};
public:
void OFunc(){
std::cout << "OFunc()" << std::endl;
}
aBar Bar;
};
int main(){
Foo foo;
foo.OFunc();
foo.Bar.IFunc();
}
However, in order to use this, one must create an instance of each grouping object (in the pseudocode example one instance of Get and another one of Set, in the dummy example one instance of aBar). Is there a way to achieve this functionality in a different way (maybe using the actual scope operator :: to indicate the member that is to be called resides within an inner scope)?
I don't really understand the reason why you want to achieve such a behaviour. However, if you want to achieve something like that you may get inspired by the following (although I won't ever use some code like this in any project, still not seeing one plausible reason):
#include <iostream>
class Interface1
{
protected:
virtual ~Interface1() {}
virtual void DoStuff1() = 0;
};
class Interface2
{
protected:
virtual ~Interface2() {}
virtual void DoStuff2() = 0;
};
class Interface3
{
protected:
virtual ~Interface3() {}
virtual void DoStuff3() = 0;
};
class Container;
class Grouper1
{
public:
static void DoStuff1(Container& arContainer);
static void DoStuff2(Container& arContainer);
};
class Grouper2
{
public:
static void DoStuff3(Container& arContainer);
};
class Container : public Interface1, public Interface2, public Interface3
{
public:
virtual ~Container() {}
private:
friend class Grouper1;
friend class Grouper2;
virtual void DoStuff1() { printf("DoStuff1()\n"); }
virtual void DoStuff2() { printf("DoStuff2()\n"); }
virtual void DoStuff3() { printf("DoStuff3()\n"); }
};
void Grouper1::DoStuff1(Container& arContainer) { arContainer.DoStuff1(); }
void Grouper1::DoStuff2(Container& arContainer) { arContainer.DoStuff2(); }
void Grouper2::DoStuff3(Container& arContainer) { arContainer.DoStuff3(); }
int main(int aArgc, char** aArgv)
{
Container c;
Grouper1::DoStuff1(c);
Grouper1::DoStuff2(c);
Grouper2::DoStuff3(c);
return 0;
}
This way your Container can implement some interfaces and your Groupers provide static functions (grouped) to access those methods (although you need to pass the actual Container, you want to work on). But definitely you won't achieve namespace-like access if you don't provide some helper functions/classes (as Grouper1, Grouper2).
Imagine I have a class 'BaseA' that contains a collection of items 'ItemA'.
Now I want to extend 'BaseA' to add extra capabilities, so I derive 'DerivedA' from 'BaseA'.
One characteristic of 'DerivedA' is that it has to handle more sophisticated 'DerivedITemA' items instead of 'ItemA' ones.
class BaseA {
protected:
vector<ItemA> x;
void m1(int i) { x.m1(i); }
};
class ItemA {
protected:
void m1(int i) { ... }
};
class DerivedItemA : public ItemA {
void m2(int i) { ... }
};
Now I would like to handle something of this sort:
class DerivedA : public BaseA {
vector<DerivedItemA> x;
void m2(int i) { x[i].m2(); }
};
I.e. have my Derived class handle derived items. The above definition of x is incorrect as it clashes with the one in BaseA. But the idea is I want to be able to reuse all methods in BaseA that handle x as long as they deal with ItemA elements and have the extended methods in DerivedA to handle the extra intricacies of DerivedItemA type of data
Any suggestion? My current thoughts are in the lines of defining a new datatype for x (VectorOfItemA for instance) and derive from it VectorOfDerivedItemA. I wonder if there is a simpler / better solution.
Thanks
I believe you need to have pointers in your vectors in order to handle this. I'm a little confused what value to pass to m1 and m2 since i appears to be an index, but here's my guess:
class BaseA {
protected:
vector<ItemA*> x;
void m1(int i) { x[i]->m1(i); }
};
class ItemA {
protected:
void m1(int i) { ... }
};
class DerivedItemA : public ItemA {
void m2(int i) { ... }
};
class DerivedA : public BaseA {
vector<DerivedItemA*> y; //don't shadow the base class vector!
void m2(int i) { y[i]->m2(i); }
};
Then, when you add an item in DerivedA, add it to both x and y. That way BaseA can do it's thing to the pointer in x and DerivedA can do its thing on the pointer in y.
Edit: you'll also need to provide a virtual method for adding items otherwise you might get things added to BaseA.x that don't get added to DerivedA.y.
Do you own all the classes? If so, you can refactor into a template base class instead.
template <typename ITEM>
class BaseT {
protected:
vector<ITEM> x;
void m1(int i) { x[i].m1(); }
};
typedef BaseT<ItemA> BaseA;
class DerivedA: public BaseT<DerivedItemA> {
void m2(int i) { x[i].m2(); }
};
If you intend to re-use code that takes BaseA to also accept a DerivedA, then you may need to modify them to be template functions/classes as well.
Otherwise, you will need some kind of "polymorphic" base object for the vector. You can look at Retrieve data from heterogeneous std::list (or my follow up question: unique_ptr member, private copy constructor versus move constructor) for one such approach.
As an alternative to a polymorphic item, you can define an interface for your base.
class BaseI {
protected:
virtual void m1(int) = 0;
//... other interfaces
public:
virtual ~BaseI () {}
//... other public interfaces
};
template <typename ITEM>
class BaseT : public BaseI {
protected:
vector<ITEM> x;
void m1(int i) { x[i].m1(); }
//...implement the other interfaces
};
//...
Now, code that takes a BaseA needs to be refactored to take a BaseI instead. That new code will be able to accept a DerivedA as well.
You may try to use Curiously Recurring Template Pattern - CRTP:
live demo
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;
struct Item
{
void m1(int i)
{
cout << "m1(" << i << ")" << endl;
}
};
struct DerivedItem : Item
{
void m2(int i)
{
cout << "m2(" << i << ")" << endl;
}
};
template<typename Derived>
struct IBase
{
void m1(int i)
{
for(auto &&z : static_cast<Derived*>(this)->x)
{
z.m1(i);
}
}
};
template<typename Derived>
struct IDerivedBase: IBase<Derived>
{
void m2(int i)
{
for(auto &&z : static_cast<Derived*>(this)->x)
{
z.m2(i);
}
}
};
struct Base : IBase<Base>
{
vector<Item> x;
};
struct DerivedBase : IDerivedBase<DerivedBase>
{
vector<DerivedItem> x;
};
int main()
{
Base b;
b.x.resize(3);
DerivedBase d;
d.x.resize(1);
b.m1(11);
d.m1(22);
d.m2(33);
}
Output is:
m1(11)
m1(11)
m1(11)
m1(22)
m2(33)
Vector will contain either all elements as ItamA in BaseA instantiations or all elements of DerivedItemA in DerivedA instantiaions. There is no need to mix.
There is no any mix at this approach:
Base has only vector<Item> providing m1 method
DerivedBase has only vector<DerivedItem> providing m1 and m2 methods.
However, without knowing real usage pattern - it is hard to guess what you need. Maybe for your case two standalone vectors would be enough:
vector<Item> x1;
vector<DerivedItem> x2;
and just define stand-alone functions for them.