CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9
  1. #1
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    Upward casting (vector of boost::shared_ptr)

    Code:
    // In my header file
    class Source
    {
    	// Whatever
    };
    
    
    class FileSource : public Source
    {
    	// Whatever
    };
    
    
    void SomeFunc(vector<boost::shared_ptr<FileSource>>& array);
    Code:
    // In my source file
    void SomeOtherFunc()
    {
    	typedef vector<boost::shared_ptr<Source>> Sources;
    
    	// Do something to populate the Sources array (assume
    	// that it actually gets populated with FileSource* )
    
    	// Now pass it to SomeFunc
    	SomeFunc(Sources);
    }
    Sources actually gets populated with FileSource*

    SomeFunc() is expecting a vector of FileSource*

    So how do I call it with an array of Source*? Simple casting doesn't seem to work here but I guess there must be some way around it...
    "A problem well stated is a problem half solved.” - Charles F. Kettering

  2. #2
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    Re: Upward casting (vector of boost::shared_ptr)

    Doh! I'm over thinking this. The obvious solution is to redefine SomeFunc() to this:-

    Code:
    void SomeFunc(vector<boost::shared_ptr<Source>>& array);
    Then (for each entry in the array) to use boost:ynamic_pointer_cast() to get from the Source* to FileSource*

    I'd still be interested to find out if there's a solution to my original question though...
    "A problem well stated is a problem half solved.” - Charles F. Kettering

  3. #3
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: Upward casting (vector of boost::shared_ptr)

    If you know that your vector only contains FileSource*, declare it as such.
    If you don't - don't pass it to that function.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  4. #4
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: Upward casting (vector of boost::shared_ptr)

    And option #3:
    let SomeFunc() to accept an array of Source*, and then ignore anything that is not FileSource*.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  5. #5
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Upward casting (vector of boost::shared_ptr)

    Quote Originally Posted by John E View Post
    Code:
    void SomeFunc(vector<boost::shared_ptr<FileSource>>& array);
    Code:
    // In my source file
    void SomeOtherFunc()
    {
    	typedef vector<boost::shared_ptr<Source>> Sources;
    
    	// Do something to populate the Sources array (assume
    	// that it actually gets populated with FileSource* )
    
    	// Now pass it to SomeFunc
    	SomeFunc(Sources);
    }
    Sources actually gets populated with FileSource*

    SomeFunc() is expecting a vector of FileSource*

    So how do I call it with an array of Source*? Simple casting doesn't seem to work here but I guess there must be some way around it...
    The answer is pretty obvious. As long as SomeFunc expects for FileSources you allocate another vector of FileSources specifically, you walk along Sources and skim the FileSources only, and fill the other vector with the exact values. And you feed SomeFunc with what it wants but not with an unsorted stuff.
    Best regards,
    Igor

  6. #6
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    Re: Upward casting (vector of boost::shared_ptr)

    Hi Igor. I probably haven't explained enough of the problem. FileSource is a class derived from Source. There can be other derived classes too - let's say FooSource and BarSource. The function that fills the array will let me know whether the entries are FileSource* or FooSource* or BarSource*. And depending on which type they are, a specific handler will get called that handles that particular type (at any given time, the array will never contain mixed types).

    So, knowing that there are never mixed types in the array, I wondered if it was possible to declare each handler function with the type that it expects - e.g.

    Code:
    void FileSourceHandler(vector<boost::shared_ptr<FileSource>>& array);
    void FooSourceHandler(vector<boost::shared_ptr<FooSource>>& array);
    void BarSourceHandler(vector<boost::shared_ptr<BarSource>>& array);
    Obviously, if I was passing individual elements to each function I could use boost:ynamic_pointer_cast() and pass in a pointer to the correct type. But I was wondering if something similar could be done for an array. In other words, if I have an array of pointers to type A can I somehow make it look like an array of pointers to type B? After all, it's just an array of pointers. It's no big deal if it can't be done because I can easily pass in an array of Source* and then cast each element to the correct type (within the handler functions) but I just wondered if there was some clever technique that I'm missing which could cast the entire array. There probably isn't but I was just being curious.
    Last edited by John E; August 10th, 2013 at 01:56 AM.
    "A problem well stated is a problem half solved.” - Charles F. Kettering

  7. #7
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Upward casting (vector of boost::shared_ptr)

    Quote Originally Posted by John E View Post
    Hi Igor. I probably haven't explained enough of the problem. FileSource is a class derived from Source. There can be other derived classes too - let's say FooSource and BarSource. The function that fills the array will let me know whether the entries are FileSource* or FooSource* or BarSource*. And depending on which type they are, a specific handler will get called that handles that particular type (at any given time, the array will never contain mixed types).
    Maybe the design should have been template-based and then use a strategy, template, or even a visitor design pattern to implement your functions. Then no casting would have been necessary.

    The goal is to see what is common, and make an abstraction from the common pieces. If that is done correctly, the solution is typesafe and no need for casts or conversions as you've seemed to be focusing on (read what you have stated in the quote, and you see that all of these smart pointer vectors perform the same set of general steps). I've seen too many times when programmers just jump in and start writing code, and not see the overall picture as to how to design the code properly, i.e. they purely think on a functional basis instead of a class/design pattern basis.

    Second:
    Code:
    void FileSourceHandler(vector<boost::shared_ptr<FileSource>>& array);
    void FooSourceHandler(vector<boost::shared_ptr<FooSource>>& array);
    void BarSourceHandler(vector<boost::shared_ptr<BarSource>>& array);
    Why not just do this:
    Code:
    void SourceHandler(vector<boost::shared_ptr<FileSource>>& array);
    void SourceHandler(vector<boost::shared_ptr<FooSource>>& array);
    void SourceHandler(vector<boost::shared_ptr<BarSource>>& array);
    But having said this, I think you need to take a step back and look at the design here. What if there is another Source? Are you going to create another set of similarly named functions to handle this type? In other words, n types, therefore n different functions? Or is there a way to add types and not need to change any boilerplate code, and the only change necessary is to create the new type and have the type maintain its own handler?

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; August 10th, 2013 at 04:43 PM.

  8. #8
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Upward casting (vector of boost::shared_ptr)

    For example:
    Code:
    #include <vector>
    #include <algorithm>
    //... other includes
    
    using namespace std;
    
    class Source{};
    
    class FileSource : public Source
    {
        public:
           void CustomFunction() {}  // some custom function for this object
    };
    
    class FooSource : public Source
    {
        public:
           void CustomFunction() {}  // some custom function for this object
    };
    
    class MyUnderivedClass
    {
        public:
           void CustomFunction() {}  // some custom function for this object
    };    
    //...
    template <typename T>
    struct CustomHandler
    {
           void operator()(boost::shared_ptr<T>& ptr)
           {  ptr->CustomFunction();   } // call the custom function
    };
    
    template <typename T>
    void SourceHandler(vector<boost::shared_ptr<T> >& array)
    {
          for_each(array.begin(), array.end(), CustomHandler<T>());
    }
    
    int main()
    {
        vector<boost::shared_ptr<FileSource>> theArray;
        SourceHandler(theArray);
        vector<boost::shared_ptr<FooSource>> theArray2;
        SourceHandler(theArray2);
        vector<boost::shared_ptr<MyUnderivedClass>> theArray3;
        SourceHandler(theArray3);
    }
    All that is needed to add a new type is to make sure it is a class/struct that has an accessible CustomFunction. There is no need to change at all the SourceHandler function or the CustomHandler function object (this would be the boilerplate code). The main() function looks just like an ordinary main() function that declares the various vector<smart_ptr> arrays, and then calls the function to handle each item using for_each().

    Also, note that there is no typecasting, no dynamic casting, no upcasting, etc.. anywhere. As a matter of fact, the FileSource and FooSource need not even be derived from any object. All they need is a CustomFunction() function, as the MyUnderivedClass shows. To go further, you can even have the CustomFunction abstracted into a function pointer/object, and that passed to the SourceHandler/CustomHandler function/functor. In other words, a completely generic solution can be obtained, all without typecasting.

    The bottom line is that your original code/design description basically told us the data types used must follow the same pattern, but the data types are different. Whenever you see that (different data types/same pattern), the first thing that should come into mind is "templates", and not casting all over the place, using void pointers, using the error-prone "copy-paste, change data type in the copy" or other 'C'-ish or 'C'-like solutions. Even overloaded functions may not be the answer because again, the overloads more than likely contain duplicated code (thus the "copy-paste and change the copy to fit my data type" scenario was done, when it should be avoided).

    Once the general design is done, then the customizations come into play almost automatically (like in my example) or may require further refactoring to make them look generic (even though they are customizations). This may require template specialization, or passing the custom function as a template argument itself (akin to policy-based design).

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; August 12th, 2013 at 12:48 PM.

  9. #9
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,835

    Re: Upward casting (vector of boost::shared_ptr)

    Hi Paul, that's exactly what I was looking for. At my end I'd need some extra functionality to populate the arrays but that bit's already written so it should be trivial to adapt. Thanks.
    "A problem well stated is a problem half solved.” - Charles F. Kettering

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured