Decorator Pattern and Class Templates?

Hello,

I'm not entirely sure if this is even possible, but is it possible to
create a decorator pattern in C++ using template classes?

I've written some very basic source code to try and do this myself,
and I have posted it over at codepad.org (http://codepad.org/EoxSD9AL)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <iostream>
#include <string>

using namespace std;
 
/* Component (interface) */
class ServerCall {
 
public:
  virtual int getsDataSize() = 0;
  virtual ~ServerCall() {}
};  
 
/* ConcreteComponent */
class CompanyServerCall : public ServerCall {
 
private:                  
     

protected:
       

public:
   /*XXSocket *Socket;*/
   CompanyServerCall(/* XXSocket *Sckt */){
        /* Socket = Sckt; */
   }

   ~CompanyServerCall() {

   }

   int getsDataSize() {
        int ip = 0;
  cout << "CompanyServerCall: " << "0 ";

        cout << "ip: " << ip << endl;
        return ip;
   }

};
 
/* Decorator (interface) */                                          
class ServerCallDecorator : public ServerCall {
 
private:
protected:
     ServerCall* wid;       // reference to ServerCall
 
public:
   ServerCallDecorator( ServerCall* w )  {
     wid = w;
   }
 
   int getsDataSize() {
     return wid->getsDataSize();
   }
 
   ~ServerCallDecorator() {
     delete wid;
   }
};
 

template <class T>
class TServerCallDecorator : public ServerCallDecorator {
private:
        T *arg;
public:
   TServerCallDecorator(T *shortArg, ServerCall* w ) :
ServerCallDecorator( w )
   {
    arg = shortArg;
   }

   int getsDataSize() {
      int ip = ServerCallDecorator::getsDataSize();
      cout << "   ShortServerCallDecorator: " << *arg << ":";

      /*memcpy(Socket->sData, arg, sizeof(T)); */
      ip+=sizeof(T);
      cout << " ip: " << ip << endl;
      return ip;
   }  
};

// class template specifications
template <> class TServerCallDecorator <char> : public
ServerCallDecorator {
private:
        char *arg;
public:
   TServerCallDecorator(char *strArg, ServerCall* w ) :
ServerCallDecorator( w )
   {
        arg = strArg;
   }
   int getsDataSize() {
        int ip = ServerCallDecorator::getsDataSize();
        cout << "   StringServerCallDecorator: " << arg << ";";

       /*memcpy(Socket->sData+ip, arg, strlen(arg)+1) */

        ip+=strlen(arg)+1;

        cout << " ip: " << ip << endl;

        return ip;
   }
};

int main( void ) {

   char *myStr = new char[20];
   char *myStr2 = new char[20];
   char *myStr3 = new char[50];
   short *myShort = new short;
   int *myInt = new int;

   *myShort = 1;
   *myInt = 4;

   strcpy(myStr, "myStr");
   strcpy(myStr2, "Tom");
   strcpy(myStr3, "Andy");

   CompanyServerCall* A = new CompanyServerCall(/* Socket */);
   TServerCallDecorator<short> D (myShort, A);
   TServerCallDecorator<int> E (myInt, D);
   TServerCallDecorator<char> F (myStr, E);
 
    cout << aServerCall->getsDataSize();

   return 0;
}


What I wish to do is sum the total size of the data structure
needed to send some data over an imaginary socket, given a random set
of arguments (int this case myShort, myInt, and myStr) to pass to the
server on the other side.

All of the primitive data type sizes are calculated the same way
with the exception of the "char*" whose data type has to have 1 added
to its size for calculation (hence the template specification for the
<char> data type)

When I compile this code I get a strange error that reads

1
2
3
4
5
6
7
line 126: TServerCallDecorator<int> E (myInt, D);

In function 'int main()':
Line 126: error: no matching function for call to
'TServerCallDecorator<int>::TServerCallDecorator(int*&,
TServerCallDecorator<short int>&)'
compilation terminated due to -Wfatal-errors.


I don't understand where the int*& (pointer to an address) comes from.

Thank you,
Andrew J. Leer
Please in future include the full compiler error. You are missing the possible candidate component.

1
2
3
4
5
6
   CompanyServerCall* A = new CompanyServerCall(/* Socket */);
   TServerCallDecorator<short> D (myShort, A);
   TServerCallDecorator<int> E (myInt, D); 
   TServerCallDecorator<char> F (myStr, E);
 
    cout << aServerCall->getsDataSize();


Becomes:

1
2
3
4
5
6
   CompanyServerCall* A = new CompanyServerCall(/* Socket */);
   TServerCallDecorator<short> D (myShort, A); // A is Pointer
   TServerCallDecorator<int> E (myInt, &D); // D Is not a pointer, bug!
   TServerCallDecorator<char*> F (myStr, &E); // E not a pointer, bug!
 
    cout << F.getsDataSize(); // Runtime error, because deleting local vars D and E 


Line 88 Becomes:
template <> class TServerCallDecorator <char*> : public

Line 60: delete wid; Can't go here. Because you do not know if you are being passed a pointer, or a reference to a local variable. Therefore you cannot be responsible for deleting it. This causes a runtime error.

E.g You cannot delete D, E or F. D and E are passed as reference variables and it tried to delete them causing a runtime error.

You need to decide on how you wish to implement the pattern as far as coding rules go.

Edit: Use string* instead of char*. Also, you should be declaring them in a proper embedded-chain constructor fashion.

e..g new A(new B(new C(new D())));
Last edited on
The people I work with refuse to use anything so advanced as a string* that's the only reason I don't use that (I'm sure it has it's advantages!)

(They're a bunch of C coders that think they use C++!)

But thank you for the feedback! I was very excited to receive it!
Hey it worked! Thanks a lot! :)

Also here is a link to it compiling: http://codepad.org/epgb8XnR

Here is the full working src:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
#include <string>

using namespace std;
 
/* Component (interface) */
class ServerCall {
 
public:
  virtual int getsDataSize() = 0;
  virtual ~ServerCall() {}
};  
 
/* ConcreteComponent */
class CompanyServerCall : public ServerCall {
 
private:                  
     

protected:
       

public:
   /*XXSocket *Socket;*/
   CompanyServerCall(/* XXSocket *Sckt */){
        /* Socket = Sckt; */
   }

   ~CompanyServerCall() {

   }

   int getsDataSize() {
        int ip = 0;
  cout << "CompanyServerCall: " << "0 ";

        cout << "ip: " << ip << endl;
        return ip;
   }

};
 
/* Decorator (interface) */                                          
class ServerCallDecorator : public ServerCall {
 
private:
protected:
     ServerCall* wid;       // reference to ServerCall
 
public:
   ServerCallDecorator( ServerCall* w )  {
     wid = w;
   }
 
   int getsDataSize() {
     return wid->getsDataSize();
   }
 
   ~ServerCallDecorator() {
   }
};
 

template <class T>
class TServerCallDecorator : public ServerCallDecorator {
private:
        T *arg;
public:
   TServerCallDecorator(T *shortArg, ServerCall* w ) :
ServerCallDecorator( w )
   {
    arg = shortArg;
   }

   int getsDataSize() {
      int ip = ServerCallDecorator::getsDataSize();
      cout << "   ShortServerCallDecorator: " << *arg << ":";

      /*memcpy(Socket->sData, arg, sizeof(T)); */
      ip+=sizeof(T);
      cout << " ip: " << ip << endl;
      return ip;
   }  
};

// class template specifications
template <> class TServerCallDecorator <char*> : public
ServerCallDecorator {
private:
        char *arg;
public:
   TServerCallDecorator(char *strArg, ServerCall* w ) :
ServerCallDecorator( w )
   {
        arg = strArg;
   }
   int getsDataSize() {
        int ip = ServerCallDecorator::getsDataSize();
        cout << "   StringServerCallDecorator: " << arg << ";";

       /*memcpy(Socket->sData+ip, arg, strlen(arg)+1) */

        ip+=strlen(arg)+1;

        cout << " ip: " << ip << endl;

        return ip;
   }
};

int main( void ) {

   char *myStr = new char[20];
   char *myStr2 = new char[20];
   char *myStr3 = new char[50];
   short *myShort = new short;
   int *myInt = new int;

   *myShort = 1;
   *myInt = 4;

   strcpy(myStr, "myStr");
   strcpy(myStr2, "Tom");
   strcpy(myStr3, "Andy");

   CompanyServerCall* A = new CompanyServerCall(/* Socket */);
   TServerCallDecorator<short> D (myShort, A);
   TServerCallDecorator<int> E (myInt, &D);
   TServerCallDecorator<char> F (myStr, &E);
 
   cout << F.getsDataSize();

   return 0;
}

Last edited on
Topic archived. No new replies allowed.