Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
programming:cpp-style-tips [2008/01/30 07:37] 127.0.0.1 external edit |
programming:cpp-style-tips [2013/09/19 16:41] (current) |
||
---|---|---|---|
Line 5: | Line 5: | ||
It is a very good thing to make a modular architecture. It permits creating several implementation for one functionnality (several ways to do it), and to easily switch from one to the other, or change a part of the program. | It is a very good thing to make a modular architecture. It permits creating several implementation for one functionnality (several ways to do it), and to easily switch from one to the other, or change a part of the program. | ||
+ | |||
+ | ==== Inheritance ==== | ||
The most obvious way to do that is inheritance. You create an interface, which defines what your implementation must be able to do, and you inheritate several implementations that do it with different ways. Then anywhere else you always use the interface class, and it will use the implementation you initialized with, no matter what it is. | The most obvious way to do that is inheritance. You create an interface, which defines what your implementation must be able to do, and you inheritate several implementations that do it with different ways. Then anywhere else you always use the interface class, and it will use the implementation you initialized with, no matter what it is. | ||
Line 56: | Line 58: | ||
</ | </ | ||
- | It does the job, but it is not the best way, because all functions must be virtual, so they cannot be inlined. | + | It does the job, but it is not the best way, because all functions must be virtual, so they cannot be inlined |
Moreover this does not really respect the philosophy of inheritance. Inheritance represents the relationship "is a kind of". But '' | Moreover this does not really respect the philosophy of inheritance. Inheritance represents the relationship "is a kind of". But '' | ||
Eventually, it does not always work. If you create the '' | Eventually, it does not always work. If you create the '' | ||
+ | |||
+ | ==== Templates ==== | ||
There is another solution, which consists in using templates. Give the '' | There is another solution, which consists in using templates. Give the '' | ||
Line 133: | Line 137: | ||
</ | </ | ||
- | It works. But you have to be sure that your counter is signed, and it won't work in some other cases, if your counter is not just an integer but a pointer scanning | + | It works. But it won't work in some other cases, if your counter is not just an integer but a pointer scanning a list for example. It's ugly. |
A nicer workaround : | A nicer workaround : | ||
Line 243: | Line 247: | ||
</ | </ | ||
+ | ===== Copy of abstract objects ===== | ||
+ | |||
+ | ==== Clone function ==== | ||
+ | |||
+ | You have an abstract class, and several implementations of this class. You have a pointer to the abstract class, but you don't know which implementations it is, and you want to make a copy of this object. The solution is to use a '' | ||
+ | |||
+ | <code cpp> | ||
+ | class Descriptor | ||
+ | { | ||
+ | | ||
+ | virtual Descriptor* clone() = 0; | ||
+ | }; | ||
+ | |||
+ | class Type1Descriptor: | ||
+ | { | ||
+ | | ||
+ | virtual Descriptor* clone() | ||
+ | { | ||
+ | return new Type1Descriptor(*this); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | class AnotherClass | ||
+ | { | ||
+ | Descriptor *my_descriptor; | ||
+ | | ||
+ | AnotherClass(Descriptor *modelDescriptor) | ||
+ | { | ||
+ | my_descriptor = modelDescriptor-> | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | ==== Factory model ==== | ||
+ | |||
+ | If you just want to copy the configuration parameters of the class, you can create a Factory class that will have the same constructor parameters than your class and will store them internally, and that has a '' | ||
+ | |||
+ | <code cpp> | ||
+ | class Descriptor | ||
+ | { | ||
+ | | ||
+ | virtual void describe() = 0; | ||
+ | Descriptor(int param1, int param2): param1(param1), | ||
+ | }; | ||
+ | |||
+ | class DescriptorFactory | ||
+ | { | ||
+ | | ||
+ | virtual Descriptor* create() const = 0; | ||
+ | } | ||
+ | |||
+ | class Type1Descriptor: | ||
+ | { | ||
+ | int param1; | ||
+ | int param2; | ||
+ | int internalData; | ||
+ | | ||
+ | Descriptor(int param1, int param2): param1(param1), | ||
+ | virtual void describe() { ... } | ||
+ | }; | ||
+ | |||
+ | class Type1DescriptorFactory: | ||
+ | { | ||
+ | int param1; | ||
+ | int param2; | ||
+ | | ||
+ | Descriptor(int param1, int param2): param1(param1), | ||
+ | virtual Descriptor* create() const | ||
+ | { | ||
+ | return new Type1Descriptor(param1, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | class AnotherClass | ||
+ | { | ||
+ | Descriptor *my_descriptor; | ||
+ | | ||
+ | AnotherClass(DescriptorFactory *descriptorFactory) | ||
+ | { | ||
+ | my_descriptor = descriptorFactory-> | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | ===== Inherited parameters ===== | ||
+ | |||
+ | |||
+ | First see [[cpp-style-tips# | ||
+ | |||
+ | You want two descriptors of same type being able to merge. So you have to declare it in the base class, with the base type, in order to be able to use it in general. But you don't know how to merge two different kinds of descriptors. If you implement a " | ||
+ | |||
+ | <code cpp> | ||
+ | class Descriptor | ||
+ | { | ||
+ | | ||
+ | virtual void merge(Descriptor* desc) = 0; | ||
+ | }; | ||
+ | |||
+ | class Type1Descriptor | ||
+ | { | ||
+ | | ||
+ | virtual void merge(Descriptor* desc) | ||
+ | { | ||
+ | Type1Descriptor *desc1 = dynamic_cast< | ||
+ | if (desc1 == NULL) | ||
+ | { | ||
+ | std::cout << " | ||
+ | return; | ||
+ | } | ||
+ | // do the merging of two Type1Descriptor here | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
====== C style tips ====== | ====== C style tips ====== |