Mathieu Malaterre wrote:
On Feb 19, 2008 5:43 AM, Gonzalo Garramuño <[EMAIL PROTECTED]> wrote:
Mathieu Malaterre wrote:
Ok this was yet-another-weird-dll thingy, one cannot do:

class GDCM_EXPORT String : std::string { ... }

Please, learn a little bit more about C++.

Oh thank you ! I'll take your advice right away, mister expert. So
could you please let me know why *in my particular case* this is
wrong:
1. I did not add any data member
2. I did not overload the dstor


GDCM_EXPORT tells me you are using this in a library.

The reason this is wrong is this. Say you write a function to get a exension of a filename as uppercase:

        GDCM_EXPORT MyString get_extension( const MyString& b )
        {
           MyString ext = b.to_upper();
           // etc... do some other stuff like find '.' and substr
           return ext;
        }

Now... this will work. But.... now func() can only be used with your particular MyString class. However, if you had done:

        namespace str {
           // to_upper implementation not shown
           GDCM_EXPORT std::string to_upper( const std::string& b );

           GDCM_EXPORT std::string get_extension( const std::string& b )
           {
             std::string ext = to_upper( b );
             // etc... do some other stuff like find '.' and substr
             return ext;
           }
        }


With this, the code for both to_upper() and get_extension() can be safely be reused and works for *all* std::string objects. You don't force people to use your own string library. This makes your library more attractive and easier to reuse in other code.

Even, if you did not do 1 or 2, you might have done 3:
        3. Yo might have overloaded (replaced) a string function.

class MyString : public std::string
{
public:
   // silly example, but same applies to add, operator<<, etc.
   size_type size() { return std::string::size() + 1; }
};

int main()
{
 MyString* s = new MyString;
 std::string* c = static_cast< std::string* >( s ); // correct
 std::cerr << c->size() << std::endl;   // which size() gets called?
                                        // not yours,
                                        // but the one in std::string
 return 0;
}

This example for 3) is very simple and obvious but in big programs this issue may be more confusing as the distintion of what a pointer really points to becomes more blurry.

If you have only added non-conflicting functions in MyString to std::string, what you have is safe but potentially not so beneficial. You might either do as I showed and place your additional functions in a namespace and keep using std::string everywhere (which makes your library nice to use and probably popular) or create your own string class, without deriving anything (and yes, you do need to create a lot of code for doing a good string class -- it is C++ after all), or create a proxy string class thru containment of std::string (which is like creating your own string class from scratch, but a tad simpler):

class MyString
{
std::string str;

public:
     typedef std::string::size_type size_type;
     // other typedefs similar to std::string...

public:
     MyString() {}
     MyString(const MyString& b) : str(b.str) {}
     MyString(const std::string& b) : str(b)  {}

    // auto cast to string - optional (only if lazy, may not be wanted)
    operator std::string() const { return str; }

    // dispatch size function
    inline size_type size() const { return str.size(); }

    // my functions - not shown
    void to_upper();

    // .... dispatch others, etc...
    // also remember to add operator=(const std::string& b)
};

This avoids you having to actually write your (potentially buggy) code to the string functions, as you just dispatch the operations to the std::string inside your class. And the operator to std::string() and copy constructor of std::string allows your class to interact with std::string functions and elements rather seamlessly. It is still verbose, but not *THAT* much. And the code is probably safer to use through pointers and easy to extend without conflicts.


Please do not copy some random comment found on the internet and
instead comment on my particular implementation with the following 1
and 2 restrictions. Thanks.


It is not some "random comment". It is good design advice that sadly applies to all C++ STL classes.

For more information, refer to a good C++ book. IIRCC, Scott Meyer's Effective STL and Effective C++, covers this and other problems with all the pitfalls in a very thorough fashion.


--
Gonzalo Garramuño
[EMAIL PROTECTED]

AMD4400 - ASUS48N-E
GeForce7300GT
Xubuntu Gutsy
_______________________________________________
CMake mailing list
CMake@cmake.org
http://www.cmake.org/mailman/listinfo/cmake

Reply via email to