4

First off, I know I can not do it, and I think it's not a duplicate questions (this and this questions deal with the same problem, but they only want an explanation of why it does not work).

So, I have a similar concept of classes and inheritance and I would, somehow, elegantly, want to do something that's forbidden. Here's a very simple code snippet that reflects what I want to do:

#include <iostream>

class A{
protected:
    int var;
    std::vector <double> heavyVar;
public:
    A() {var=1;}
    virtual ~A() {}
    virtual void func() {
        std::cout << "Default behavior" << this->var << std::endl;
    }

    // somewhere along the way, heavyVar is filled with a lot of stuff
};

class B: public A{
protected:
    A* myA;
public:
    B(A &a) : A() {
        this->myA = &a;
        this->var = this->myA->var;
             // copy some simple data, e.g. flags
             // but don't copy a heavy vector variable
    }
    virtual ~B() {}
    virtual void func() {
        this->myA->func();
        std::cout << "This class is a decorator interface only" << std::endl;
    }
};

class C: public B{
private:
    int lotsOfCalc(const std::vector <double> &hv){
        // do some calculations with the vector contents
    }
public:
    C(A &a) : B(a) {
        // the actual decorator
    }
    virtual ~C() {}
    virtual void func() {
        B::func(); // base functionality
        int heavyCalc = lotsOfCalc(this->myA->heavyVar); // illegal
            // here, I actually access a heavy object (not int), and thus
            // would not like to copy it
        std::cout << "Expanded functionality " << heavyCalc << std::endl;
    }
};

int main(void){
    A a;
    B b(a);
    C c(a);
    a.func();
    b.func();
    c.func();
    return 0;
}

The reason for doing this is that I'm actually trying to implement a Decorator Pattern (class B has the myA inner variable that I want to decorate), but I would also like to use some of the protected members of class A while doing the "decorated" calculations (in class B and all of it's subclasses). Hence, this example is not a proper example of a decorator (not even a simple one). In the example, I only focused on demonstrating the problematic functionality (what I want to use but I can't). Not even all the classes/interfaces needed to implement a Decorator pattern are used in this example (I don't have an abstract base class interface, inherited by concrete base class instances as well as an abstract decorator intreface, to be used as a superclass for concrete decorators). I only mention Decorators for the context (the reason I want a A* pointer).

In this particular case, I don't see much sense in making (my equivalent of) int var public (or even, writing a publicly accessible getter) for two reasons:

  • the more obvious one, I do not want the users to actually use the information directly (I have some functions that return the information relevant to and/or written in my protected variables, but not the variable value itself)
  • the protected variable in my case is much more heavy to copy than an int (it's a 2D std::vector of doubles), and copying it in to the instance of a derived class would be unnecessarily time- and memory-consuming

Right now, I have two different ways of making my code do what I want it to do, but I don't like neither of them, and I'm searching for a C++ concept that was actually intended for doing something of this sort (I can't be the first person to desire this behavior).

What I have so far and why I don't like it:

1. declaring all the (relevant) inherited classes friends to the base class:

class A{
    ....
    friend class B;
    friend class C;
};

I don't like this solution because it would force me to modify my base class every time I write a new subclass class, and this is exactly what I'm trying to avoid. (I want to use only the 'A' interface in the main modules of the system.)

2. casting the A* pointer into a pointer of the inherited class and working with that

void B::func(){
    B *uglyHack = static_cast<B*>(myA);
    std::cout << uglyHack->var + 1 << std::endl;
}

The variable name is pretty suggestive towards my feelings of using this approach, but this is the one I am using right now. Since I designed this classes, I know how to be careful and to use only the stuff that is actually implemented in class A while treating it as a class B. But, if somebody else continues the work on my project, he might not be so familiar with the code. Also, casting a variable pointer in to something that I am very well aware that it is not just feels pure evil to me.

I am trying to keep this projects' code as nice and cleanly designed as possible, so if anybody has any suggestions towards a solution that does not require the modification of a base class every now and then or usage of evil concepts, I would very much appreciate it.

Community
  • 1
  • 1
penelope
  • 8,251
  • 8
  • 45
  • 87
  • I believe that in the decorator pattern, the decorator and the actual objects *implement* an *interface*, that is, the decorator does not *extend* the actual object being implemented, only offers the same interface, and the decoration is applied only to the public interface. – David Rodríguez - dribeas Mar 30 '12 at 16:22
  • @DavidRodríguez-dribeas think I edited the explanation in just as you were typing the comment :) What you say is true, but in my actual case, the very top interface contains some data common to *every* concrete instance of the class. So, theoretically, I don't want to access any objects belonging to any of the concrete implementations, just some objects common to every instance of the class that are thus implemented in the interface. But as I just edited in the Q, the example code does not focus on implementing an example Decorator, just an example of my problem situation. – penelope Mar 30 '12 at 16:31
  • I am having a hard time understanding what it is you are trying to do. I understand you wanted to give a simple example, but right now I don't know which of the weird things in the code are important and which are not. For example, in the constructor for B you copy the var member, but then in class C you use the myA->var directly. Why was the copy necessary, and couldn't you use the copy for your calculation? Let's start there and maybe it will become clearer. – Lubo Antonov Mar 30 '12 at 16:59
  • @lucas1024 The problem is, the original example only showed what I want to access, where and how, but did not much resemble the Decorator pattern (it just contained the same object a real Decorator implementation would). In reality, I have much more than 1 or 2 vars in the base class, and the simple ones (e.g. flags) I don't mind copying, but the heavy ones (e.g. vectors - just added that) I *don't* want to copy. I was using only 1 variable in the example when you left your comment, *but* I did add the explanation of what I would really like to access in my code. – penelope Mar 30 '12 at 17:16

3 Answers3

2

I do believe that you might want to reconsider the design, but a solution to the specific question of how can I access the member? could be:

class A{
protected:
    int var;

    static int& varAccessor( A& a ) {
       return a.var;
    }
};

And then in the derived type call the protected accessor passing the member object by reference:

varAccessor( this->myA ) = 5;

Now, if you are thinking on the decorator pattern, I don't think this is the way to go. The source of the confusion is that most people don't realize that a type has two separate interfaces, the public interface towards users and the virtual interface for implementation providers (i.e. derived types) as in many cases functions are both public and virtual (i.e. the language allows binding of the two semantically different interfaces). In the Decorator pattern you use the base interface to provide an implementation. Inheritance is there so that the derived type can provide the operation for the user by means of some actual work (decoration) and then forwarding the work to the actual object. The inheritance relationship is not there for you to access the implementation object in any way through protected elements, and that in itself is dangerous. If you are passed an object of a derived type that has stricter invariants regarding that protected member (i.e. for objects of type X, var must be an odd number), the approach you are taking would let a decorator (of sorts) break the invariants of that X type that should just be decorated.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • What you are talking is actually making most sense out of all the comments here. I will think about what you wrote here some more (concerning both the A to this Q and the design problem), and maybe post the question about how I should design the system separately. I still think that decorator is the way to go, but maybe somebody will have a better suggestion. But here, that's off topic. – penelope Mar 30 '12 at 17:21
  • I think I finally found a nice way to do what I want... and if it is not too much trouble for you, I would love if you could comment on my solution since your comments and answer thus far have made me think of quite a lot of good questions concerning my code – penelope Apr 03 '12 at 17:09
0

I can't find any examples of the decorator pattern being used in this way. It looks like in C++ it's used to decorate and then delegate back to the decoratee's public abstract interface and not accessing non-public members from it.

In fact, I don't see in your example decoration happening. You've just changed the behavior in the child class which indicates to me you just want plain inheritance (consider that if you use your B to decorate another B the effects don't end up chaining like it would in a normal decoration).

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • That's true, I didn't put any actual decoration in to my code example, I only wrote the minimal example that would access the members in the same way I would like to access them, to keep the question as focused on *my problem* as I could. I will now expand my example code a little bit if you think this way it is confusing. – penelope Mar 30 '12 at 16:08
0

I think I found a nice way to do what I want in the inheritance structure I have.

Firstly, in the base class (the one that is a base for all the other classes, as well as abstract base class interface in the Decorator Pattern), I add a friend class declaration only for the first subclass (the one that would be acting as abstract decorator interface):

class A{

    ....
    friend class B;
};

Then, I add protected access functions in the subclass for all the interesting variables in the base class:

class B : public A{

    ...
    protected:
        A *myA;
        int getAVar() {return myA->var;}
        std::vector <double> &getAHeavyVar {return myA->heavyVar;}
};

And finally, I can access just the things I need from all the classes that inherit class B (the ones that would be concrete decorators) in a controlled manner (as opposed to static_cast<>) through the access function without the need to make all the subclasses of B friends of class A:

class C : public B{

    ....
    public:
        virtual void func() {
        B::func(); // base functionality
        int heavyCalc = lotsOfCalc(this->getAHeavyVar); // legal now!
            // here, I actually access a heavy object (not int), and thus
            // would not like to copy it
        std::cout << "Expanded functionality " << heavyCalc << std::endl;
        std::cout << "And also the int: " << this->getAVar << std::endl;
            // this time, completely legal
    }
};

I was also trying to give only certain functions in the class B a friend access (declaring them as friend functions) but that did not work since I would need to declare the functions inside of class B before the friend declaration in class A. Since in this case class B inherits class A, that would give me circular dependency (forward declaration of class B is not enough for using only friend functions, but it works fine for a friend class declaration).

penelope
  • 8,251
  • 8
  • 45
  • 87
  • 1
    You asked me to comment: the design issue is still present. The two interfaces are still confused, you are inheriting from a type that is not an interface just to borrow the interface and then forcing access to members that don't belong to you. Those are issues with the design not the implementation. What you have here is an implementation of that design with the same issues that it had before. – David Rodríguez - dribeas Apr 03 '12 at 17:33
  • @DavidRodríguez-dribeas Thank you very much for your comment. I posted the design issue as a [separate](http://stackoverflow.com/questions/10007600/design-pattern-appropriate-for-a-modular-feature-matching-application) question, so hopefully somebody will have a better way to go than I currently do. – penelope Apr 04 '12 at 08:39