Let's say I have the following code:
class A {
public:
void doSomething(B* b);
}
class B {
}
How would I describe this in a UML diagram? My first thought is that A uses B, so there should be a dotted line from A to B. But in some of the school papers (this is a very tiny part of a school assignment report) they seem to use the aggregation symbol (empty diamond and solid line).
That doesn't seem right to me - if A actually contained a pointer to B as a member, that seems right. But when only some methods use a pointer to B, and don't store it in any member variables, it seems wrong.
What's right here?
(I could ask my teachers but they usually take really long to respond to this type of question... and honestly, I trust the collective brain trust of Stackoverflow more :) )
You should use a simple dependency between A and B:
A does just use B as parameter in an operation. If you have some attribute of type B then you would use an association. Aggregation give only a little extra semantics and you can (/should) leave it out unless you know that you want to transport some specific information.
There should NOT be any arrow between class A and class B. Arrows between classes are used to indicate "associations".
An association indicates that the system you are developing stores
links of some kind between the instances of the associated types.
Source: Properties of associations on UML class diagrams
To capture/represent void doSomething(B* b); you might try using activity diagram, for more see this link.
Related
If I have a class A which contains a pointer to a class B and a method which takes in input a pointer to class B
class A {
private:
B* attribute;
public:
void method(B* par);
}
how can I describe it in a UML class diagram? Do I have to use *? What kind of composition is it?
In UML it is not as important to show whether it is a pointer or not. Why? Because, you may be using UML describing an OOD for a language without pointers.
Quick answer: from your code, A aggregates B (empty diamond at A class, connecting B with a solid line). That is because there is no destructor that deletes what A.attribute pointer references.
What is really important is to say what is the lifetime of the referenced object. So, for a referenced object (has relationship) that dies when the owner is destroyed, you have to use a solid (filled) diamond. This is called composition. So the owner has to manage the life time of the owned object. One such example is human has hands. The hands do not survive when the human object is destroyed.
When the diamond is not filled (aggregation), then the owner is not responsible to manage the life of the object owned. For example you will not expect to see that the owned object being deleted in the destructor. An employer has a TeamLeadRole, but when the employer is "destroyed" (i.e. left the company) then the TeamLeadRole is still available.
Now, traditionally when you see a filled diamond, you usually (not all the time) will have an object by value. Where when you see an empty diamond you may use reference, or pointer.
If your class uses another class but does not keep instances (or references/pointers) to that class, then you can denote dependency by just a simple line (solid) between the objects. That means there is a relationship is called association.
A plain C++ pointer directly corresponds to a reference property in a UML class diagram, as shown in the following diagram:
Such a reference property expresses a uni-directional (binary) association, as shown in the following diagram:
Notice the "dot" at the B side of the association line. It means that the association end with name "attribute" is owned by class A, which means that it corresponds to the reference property shown in the diagram above (the association can be replaced with the reference property). For more explanation see Chapter 5 of this tutorial.
You cannot use the C++ symbol "*" in the UML class diagram because
it is Cpp-specific, while your diagram should probably be platform-independent;
there is no need to use such a symbol in UML because it's clear that the attribute references B objects;
this symbol has a different meaning in UML (the multiplicity unbounded).
In any case, the relationship between the classes A and B is an association. It may be a composition, if you have the additional semantics of an aggregate-component relationship. Notice that your question should be worded: "What kind of association is it?" instead of "What kind of composition is it?" because composition and aggregation are special types of associations.
There IS the possibility to difference between *, & and [] fields on UML class diagrams. It is named "Type Modifier". The problem is to show it on the diagram for your tool. If you have a diagramming tool, simply draw it at the end as a stereotype of the end. But be careful not to mix it with the multiplicity! If you have a modelling tool, you"ll have to look how to do it.
But notice, that pointer/reference field is supposed to be a default one, so you needn't really specify your case in the class diagram.
If you want to show this information in a correct way, use a more detailed Composite Structure Diagram. There you can show these &,*,[] at you wish.
For different variants of association in class diagram look this my answer for the similar question:
https://stackoverflow.com/a/21478862/715269
What would be the best representation of a C/C++ function pointer (fp) in an UML structural diagram?
I'm thinking about using an interface element, may be even if 'degenerate' with the constraint of having at most a single operation declared.
I found some proposal in this document: C and UML Synchronization User Guide, Section 5.7.4. But this sounds quite cumbersome and not very useful in practice. Even if right from a very low level of semantic view. Here's a diagram showing their concept briefly:
IMHO in C and C++ function pointers are used as such a narrowed view of an interface which only provides a single function and it's signature. In C fp's would be used also to implement more complex interfaces declaring a struct containing a set of function pointers.
I think I can even manage to get my particular UML tool (Enterprise Architect) to forward generate the correct code, and synchronizing with code changes without harm.
My questions are:
Would declaration of fp's as part of interface elements in UML proivde a correct semantic view?
What kind of stereotype should be used for single fp declaration? At least I need to provide a typedef in code so this would be my guts choice.(I found this stereotype is proprietary for Enterprise Architect) and I need to define an appropriate stereotype to get the code generation adapted. Actually I have chosen the stereotype name 'delegate', does this have any implications or semantic collisions?
As for C++, would be nesting a 'delegate' sterotyped interface with in a class element enough to express a class member function pointer correctly?
Here's a sample diagram of my thoughts for C language representation:
This is the C code that should be generated from the above model:
struct Interface1;
typedef int (*CallbackFunc)(struct Interface1*);
typedef struct Interface1
{
typedef void (*func1Ptr)(struct Interface1*, int, char*);
typedef int (*func2Ptr)(struct Interface1*, char*);
typedef int (*func3Ptr)(struct Interface1*, CallbackFunc);
func1Ptr func1;
func2Ptr func2;
func3Ptr func3;
void* instance;
};
/* The following extern declarations are only dummies to satisfy code
* reverse engineering, and never should be called.
*/
extern void func1(struct Interface1* self, int p1, char* p2) = 0;
extern int func2(struct Interface1* self, char*) = 0;
extern int func3(struct Interface1* self, CallbackFunc p1) = 0;
EDIT:
The whole problem boils down what would be the best way with the UML tool at hand and its specific code engineering capabilities. Thus I have added the enterprise-architect tag.
EA's help file has the following to say on the subject of function pointers:
When importing C++ source code, Enterprise Architect ignores function pointer declarations. To import them into your model you could create a typedef to define a function pointer type, then declare function pointers using that type. Function pointers declared in this way are imported as attributes of the function pointer type.
Note "could." This is from the C++ section, the C section doesn't mention function pointers at all. So they're not well supported, which in turn is of course due to the gap between the modelling and programming communities: non-trivial language concepts are simply not supported in UML, so any solution will by necessity be tool-specific.
My suggestion is a bit involved and it's a little bit hacky, but I think it should work pretty well.
Because in UML operations are not first-class and cannot be used as data types, my response is to create first-class entities for them - in other words, define function pointer types as classes.
These classes will serve two purposes: the class name will reflect the function's type signature so as to make it look familiar to the programmer in the diagrams, while a set of tagged values will represent the actual parameter and return types for use in code generation.
0) You may want to set up an MDG Technology for steps 1-4.
1) Define a tagged value type "retval" with the Detail "Type=RefGUID;Values=Class;"
2) Define a further set of tagged value types with the same Detail named "par1", "par2" and so on.
3) Define a profile with a Class stereotype "funptr" containing a "retval" tagged value (but no "par" tags).
4) Modify the code generation scripts Attribute Declaration and Parameter to retrieve the "retval" (always) and "par1" - "parN" (where defined) and generate correct syntax for them. This will be the tricky bit and I haven't actually done this. I think it can be done without too much effort, but you'll have to try it. You should also make sure that no code is generated for "funptr" class definitions as they represent anonymous types, not typedefs.
5) In your target project, define a set of classes to represent the primitive C types.
With this, you can define a function pointer type as a «funptr» class with a name like "long(*)(char)" for a function that takes a char and returns a long.
In the "retval" tag, select the "long" class you defined in step 4.
Add the "par1" tag manually, and select the "char" class as above.
You can now use this class as the type of an attribute or parameter, or anywhere else where EA allows a class reference (such as in the "par1" tag of a different «funptr» class; this allows you to easily create pointer types for functions where one of the parameters is itself of a function pointer type).
The hackiest bit here is the numbered "par1" - "parN" tags. While it is possible in EA to define several tags with the same name (you may have to change the tagged value window options to see them), I don't think you could retrieve the different values in the code generation script (and even if you could I don't think the order would necessarily be preserved, and parameter order is important in C). So you'd need to decide the maximum number of parameters beforehand. Not a huge problem in practice; setting up say 20 parameters should be plenty.
This method is of no help for reverse engineering, as EA 9 does not allow you to customize the reverse-engineering process. However, the upcoming EA 10 (currently in RC 1) will allow this, although I haven't looked at it myself so I don't know what form this will take.
Defining of function pointers is out of scope of UML specification. What is more, it is language-specific feature that is not supported by many UML modeling software. So I think that the general answer to your first question suggests avoiding of this feature. Tricks you provided are relevant to Enterprise Architect only and are not compatible with other UML modeling tools. Here is how function pointers is supported in some other UML software:
MagicDraw UML uses <<C++FunctionPtr>> stereotypes for FP class members and <<C++FunctionSignature>> for function prototype.
Sample of code (taken from official site -- see "Modeling typedef and function pointer for C++ code generation" viewlet):
class Pointer
{
void (f*) ( int i );
}
Corresponding UML model:
Objecteering defines FP attributes with corresponding C++ TypeExpr note.
Rational Software Architect from IBM doesn't support function pointers. User might add them to generated code in user-defined sections that are leaved untouched during code->UML and UML->code transformations.
Seems correct to me. I'm not sure you should dive into the low-level details of descripting the type and relation of your single function pointer. I usually find that description an interface is enough detalization without the need to decompose the internal elements of it.
I think you could virtually wrap the function pointer with a class. I think UML has not to be blueprint level to the code, documenting the concept is more important.
My feeling is that you desire to map UML interfaces to the struct-with-function-pointers C idiom.
Interface1 is the important element in your model. Declaring function pointer object types all over the place will make your diagrams illegible.
Enterprise Architect allows you to specify your own code generators. Look for the Code Template Framework. You should be able to modify the preexisting code generator for C with the aid of a new stereotype or two.
I have been able to get something sort of working with Enterprise Architect. Its a bit of a hacky solution, but it meets my needs. What I did:
Create a new class stereotype named FuncPtr. I followed the guide here: http://www.sparxsystems.com/enterprise_architect_user_guide/10/extending_uml_models/addingelementsandmetaclass.html
When I did this I made a new view for the profile. So I can keep it contained outside of my main project.
Modified the Class code templates. Basically selecting the C language and start with the Class Template and hit the 'Add New Stereotype Override' and add in FuncPtr as a new override.
Add in the following code to that new template:
%PI="\n"%
%ClassNotes%
typedef %classTag:"returnType"% (*%className%)(
%list="Attribute" #separator=",\n" #indent=" "%
);
Modified the Attribute Declaration code template. Same way as before, adding in a new Stereotype
Add in the following code to the new template:
%PI=""% %attConst=="T" ? "const" : ""%
%attType%
%attContainment=="By Reference" ? "*" : ""%
%attName%
That's all that I had to do to get function pointers in place in Enterprise Architect. When I want to define a function pointer I just:
Create a regular class
Add in the tag 'returnType' with the type of return I want
Add in attributes for the parameters.
This way it'll create a new type that can be included as attributes or parameters in other classes (structures), and operators. I didn't make it an operator itself because then it wouldn't have been referenced inside the tool as a type you can select.
So its a bit hacky, using special stereotyped classes as typedefs to function pointers.
Like your first example I would use a Classifier but hide it away in a profile. I think they've included it for clarity of the explaining the concept; but in practice the whole idea of stereotypes is abstract away details into profiles to avoid the 'noise' problem. EA is pretty good for handling Profiles.
Where I differ from your first example is that I would Classify the Primitive Type Stereotype not the Data Type stereotype. Data Type is a Domain scope object, while Primitive Type is an atomic element with semantics defined out side the scope of UML. That is not to say you cannot add notes, especially in the profile or give it a very clear stereotype name like functionPointer.
I want to know which is better way for this problem:
A teacher can teach more than one subject or can take more than on lab or may be both in a institute. Lab,Subject,Teacher also have some other variables. I did not write them all here.
New lab,subject and teacher can be added individually. When a teacher is added I only input all variables of Teacher class and labCode and subCode. There are some Labs and Subjects which are predefined and others which are added later. I can view record of a teacher which shows his Lab and Subject details also if available.
My concepts in c++ are not too strong and I don't know which one is better for this. Should I give a pointer in Teacher class to Lab and Subject class or should I inherent them, or is there any better way to do this.
class Lab{
char labCode[20];
char labName[40];
int labYear;
//here default constructor
};
class Subject{
char subCode[20];
char subName[20];
int subYear;
//here default constructor
};
//-------------------------------------
class Teacher{
char facName[30];
int teacherSubCount;
int teacherLabCount;
Subject *subject;
Lab *lab;
//here default constructor
};
//------------or should i do like this--------------
class Teacher:public Lab,public Subject{
char teacherName[30];
int teacherSubCount;
int teacherLabCount;
//here default constructor
};
If you can suggest any tutorials so I can learn the power of a pointer as my book states "pointers are very powerful c++", but they only give some simple examples :)
"Favor 'object composition' over 'class inheritance'." - Gang of Four
More specific to your classes, though, first ask yourself... "Is a Teacher a type of Lab or a type of Subject?" Clearly, the answer is "no."
In an inheritance model, the child class should itself be an instance of the parent class. Considering the Liskov Substitution Principle, that child object should be treatable as that parent object. So if there's code that's looking for a Subject you would be able to pass it a Teacher. Intuitively, that doesn't make much sense and is not an accurate representation of the real-world domain entities being modeled.
In this case you definitely want object composition instead of class inheritance. The Teacher has a Lab and has a Subject, not is a Lab or is a Subject. Indeed, if the Teacher can have multiple Labs or Subjects then the composition would simply change from a single instance class member to an array or list of some kind. Whereas the inheritance approach would break entirely in that case.
When modeling objects that represent real-world concepts like this, consider intuition of those real world concepts foremost and the technical shortcuts to implementation secondary. If it doesn't make sense in terms of what's being modeled, then it won't make sense in the code either.
Think about whether the 'is-a' (for inheritence) and 'has-a' (for aggregation) relationships make sense in your proposed solution
A Teacher is neither a Lab nor a Subject - I think you should go with the aggregation solution.
However, what you really need to get completely sorted before you get started on the code is your data model. You need to identify the relationships and multiplicity (i.e. one-to-one, one-to-many etc.) between the objects.
Inheritance implies a "is-a" relationship, while a pointer implies a "has-a" relationship.
Is a teacher a lab? Is a teacher a subject? No, it has a subject and it has a lab, so it's a "has-a" relationship. So you should use pointers, in this case.
Why inheritance wouldn't work would become apparent when you would try to change the lab of a teacher. You can easily change the object a pointer is pointing to, but replacing all the data of the base class is a lot more cumbersome.
To give an example where you would use inheritance, EnglishTeacher could inherit Teacher, because it is also a teacher, but with additional abilities.
Taking the common sense approach:
Inheritance expresses an is-a relationship. A teacher is obviously
neither a Subject or a Lab and this would be a serious eye-brow
raiser. So I'd say aggregation (a has-a or has-many) is the way to
go.
You will also need to decide if you are using value semantics
or reference semantics. That means will equality be actual equality of
objects in your program or will equality be computable through certain
parts of your object.
If you use reference semantics you will need to make sure you are
using smart-pointers or some other form of memory managment, otherwise
things get ugly really quickly.
When you inherit a class, as in your last example, think of it as extending that class' existing, defined behavior. In that vein, then, ask yourself the question: Does a "teacher" enhance the capabilities of a "lab"? To me, the answer is clear - they don't - they're entirely different objects, so inheritance isn't the ideal way to model these elements in your problem domain. A teacher has a class, a class has a subject, and so on - hence, aggregation seems to be a better path to follow.
You will understand the concept, if you look at this example:
void doExperimentsIn( Lab &room ){...}
If you derive Teacher from Lab, you will be able to do experiments inside a Teacher, too. (Which is silly.)
I have the following class cDrawObjectCreator:
class cDrawObjectCreator
{
public:
cDrawObjectCreator( cCompositeRoot *compositeObject ) { m_compositeRoot = compositeObject; }
~cDrawObjectCreator() {};
...
private:
cCompositeRoot *m_compositeRoot;
};
It is correct diagram?
or the following diagram is correct?
First one again. For the same reasons as in the previous Question.
Please read this, to see the difference between Compostion and Aggregation.
As a general rule, aggregation (hollow diamond) is a specialization of association, and composition (filled diamond) is a specialization of aggregation.
Remember the purpose of modeling is to facilitate communication so you would use different level of abstractions depending on the purpose and the stakeholders.
If you want to say that cMimicObjectCreator has an exclusive ownership of cCompositeRoot (that is, like a human / an animal body has a brain) then you would use composition (filled diamond). And if you want to say that cMimicObjectCreator has a cCompositeRoot (but not exclusively and that there are cases where the part class is not exist in the whole/container, like say...a boat with a GPS equipment) then you would use aggregation relationship.
To answer your original question, I think the first diagram is more appropriate. However remember also you can always use association relationship in place of composition or aggregation relationship if you want to be more "general".
I am about to add a class X that will be used by my three previously designed classes (A, B and C).
The new class X will contain data and functions for new features as well as provide services to the classes that use it to hide lower layers. The problem is that A, B and C will use class X quite differently, that is, use different functions of it.
My question is if I should provide an API (or Abstract Base Class in C++) for the new class X or not. If I should, should that API be per X class or per A, B and C class? I have read somewhere that an API is sometimes more closely related to that caller that the class that implements it. If I do provide one API for each caller, the API will only contain the functions that the particular caller needs.
Or should I just create a normal C++ class and let the callers use a subset of the public functions of X in each of A, B and C, although they "technically" can use them all? The functions of class X are not very likely to change neither is the need to create a similar class to X.
If I'm not completely lost in object oriented programming, one reason for providing an interface/API for a class is that code that use the interface/API doesn't need to change if you add another subclass since the caller works on the interface name and uses dynamic binding to resolve the correct subclass type.
Best regards and please let me know if anything is unclear and I'll try to answer that as quickly as possible.
Thanks,
Tomas
Are you sure all these functions belong to the same class X? Think about separating different functionality into different classes:
http://en.wikipedia.org/wiki/Low-Coupling_/_High-Cohesion_pattern
But without knowing what the functions of X are it is difficult to help further.
If things are unlikely to change then it's probably not worth the extra effort.
If you decide to, though, the question is whether new classes would implement all or just part of the functionality. For example, do they share backend storage, so all would need to be updated at once (in which case there is no point in splitting), or do they relate to entirely separate concerns in which case splitting (as suggested by #GarethOwen) is probably the way to go.