tags:

views:

232

answers:

2

Hi,

I'm putting together a presentation to show some of the productivity gains that I think C# may offer over C++. I've written some code in C# which I'd like to convert to C++. I don't have the time or up to date C++ to do the conversion justice, hence posting here.

Code to convert:

using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace LinqTest
{
    public class Vehicle
    {
        public int Id { get; set; }
        public Color Colour { get; set; }
    }

    public class Tyre
    {
        public int Id { get; set; }
        public int BikeId { get; set; }
        public int Size { get; set; }
        public string Brand { get; set; }
    }

    public class Car : Vehicle {}

    public class Bike : Vehicle {}

    public class Example
    {
        private readonly IList<Car> cars;
        private readonly IList<Tyre> bikeTyres;
        private readonly IList<Bike> bikes;

        public Example()
        {
            cars = new List<Car>
                       {
                           new Car {Id = 0, Colour = Color.Red},
                           new Car {Id = 1, Colour = Color.Blue},
                           new Car {Id = 2, Colour = Color.Green},
                           new Car {Id = 3, Colour = Color.Green}
                       };

            bikeTyres = new List<Tyre>
                            {
                                new Tyre {Id = 0, BikeId = 0, Brand = "TyreCo1", Size = 23},
                                new Tyre {Id = 1, BikeId = 0, Brand = "TyreCo1", Size = 23},
                                new Tyre {Id = 2, BikeId = 1, Brand = "TyreCo2", Size = 30},
                                new Tyre {Id = 3, BikeId = 1, Brand = "TyreCo2", Size = 30},
                                new Tyre {Id = 4, BikeId = 2, Brand = "TyreCo3", Size = 23},
                                new Tyre {Id = 5, BikeId = 2, Brand = "TyreCo3", Size = 23}
                            };

            bikes = new List<Bike>
                        {
                            new Bike {Id = 0, Colour = Color.Red},
                            new Bike {Id = 1, Colour = Color.Blue},
                            new Bike {Id = 2, Colour = Color.Green}
                        };
        }

        public IEnumerable<Vehicle> FindVehiclesByColour(Color colour)
        {
            var carVehicles = from car in cars
                           where car.Colour == colour
                           select car as Vehicle;

            var bikeVehicles = from bike in bikes
                               where bike.Colour == colour
                               select bike as Vehicle;

            return carVehicles.Union(bikeVehicles);
        }


        public IEnumerable<Bike> FindBikesByTyreSize(int size)
        {
            return (from bike in bikes
                    join tyre in bikeTyres on bike.Id equals tyre.BikeId
                    where tyre.Size == size
                    select bike).Distinct();
        }
    }
}

Thanks in advance.

+2  A: 

I'll do this for you, but for the record this is definitely a bad 'question'. This is more of a work request, which is why my answer is community wiki. There are no questions being answered here.

#include <algorithm>
#include <list>
#include <string>

namespace LinqTest
{
    // C++ does not specificy a standard GUI library.
    // This is a small hack to make the code work below.
    // In a real solution, one would probably have a real
    // Color class that stores the red, green, and blue
    // components of the colors and provides operations
    // to act upon colors.
    struct Color
    {
     static const int Red = 0;
     static const int Green = 1;
     static const int Blue = 2;

     Color(void) :
     value(0)
     {
     }

     Color(int color) :
     value(color)
     {
     }

     bool operator==(const Color& rhs) const
     {
      return value == rhs.value;
     }

     int value;
    };

    struct Vehicle
    {
     Vehicle(void) :
     Id(0)
     {
     }

     Vehicle(int id, Color colour) :
     Id(id),
     Colour(colour)
     {
     }

     bool operator==(const Vehicle& rhs) const
     {
      return Id == rhs.Id;
     }

     int Id;
     Color Colour;
    };

    struct Tyre
    {
     Tyre(void) :
     Id(0),
     BikeId(0),
     Size(0)
     {
     }

     Tyre(int id, int bikeId, int size, std::string brand) :
     Id(id),
     BikeId(bikeId),
     Size(size),
     Brand(brand)
     {
     }

     int Id;
     int BikeId;
     int Size;
     std::string Brand;
    };

    struct Car :
     public Vehicle
    {
     Car(void)
     {
     }

     Car(int id, Color colour) :
     Vehicle(id, colour)
     {
     }
    };

    struct Bike :
     public Vehicle
    {
     Bike(int id, Color colour) :
     Vehicle(id, colour)
     {
     }
    };

    class Example
    {
    // I put private up top to match yours, but most C++
    // programmers would prefer it on the bottom, justified
    // by the fact users of the class don't care or want
    // to see how the class works, they want to see how to
    // use it.
    private:
     std::list<Car> cars;
     std::list<Tyre> bikeTyres;
     std::list<Bike> bikes;

    public:
     Example(void)
     {
      cars.push_back(Car(0, Color::Red));
      cars.push_back(Car(1, Color::Blue));
      cars.push_back(Car(2, Color::Green));
      cars.push_back(Car(3, Color::Green));

      bikeTyres.push_back(Tyre(0, 0, 23, "TyreCo1"));
      bikeTyres.push_back(Tyre(1, 0, 23, "TyreCo1"));
      bikeTyres.push_back(Tyre(2, 1, 30, "TyreCo2"));
      bikeTyres.push_back(Tyre(3, 1, 30, "TyreCo2"));
      bikeTyres.push_back(Tyre(4, 2, 23, "TyreCo3"));
      bikeTyres.push_back(Tyre(5, 2, 23, "TyreCo3"));

      bikes.push_back(Bike(0, Color::Red));
      bikes.push_back(Bike(1, Color::Blue));
      bikes.push_back(Bike(2, Color::Green));
     }

     // I chose to return pointers to Vehicles to maintain any
     // polymorphic behavior, since from what I understand C#
     // would be returning references here.
     std::list<Vehicle*> FindVehiclesByColour(Color colour)
     {
      typedef std::list<Car>::iterator car_iterator;
      typedef std::list<Bike>::iterator bike_iterator;

      std::list<Vehicle*> result;

      for (car_iterator iter = cars.begin(); iter != cars.end(); ++iter)
      {
       if (iter->Colour == colour)
       {
        result.push_back(&(*iter));
       }
      }

      for (bike_iterator iter = bikes.begin(); iter != bikes.end(); ++iter)
      {
       if (iter->Colour == colour)
       {
        result.push_back(&(*iter));
       }
      }

      return result;
     }

     std::list<Bike*> FindBikesByTyreSize(int size)
     {
      typedef std::list<Tyre>::const_iterator tyre_iterator;
      typedef std::list<Bike>::iterator bike_iterator;

      std::list<Bike*> result;

      for (tyre_iterator tyreIter = bikeTyres.begin(); tyreIter != bikeTyres.end(); ++tyreIter)
      {
       if (tyreIter->Size == size)
       {
        for (bike_iterator bikeIter = bikes.begin(); bikeIter != bikes.end(); ++bikeIter)
        {
         if (tyreIter->BikeId == bikeIter->Id)
         {
          result.push_back(&(*bikeIter));
         }
        }
       }
      }

      result.sort();
      result.unique();
      return result;
     }
    };
}

Note there are a few stylistic things in there, such as Example(void) versus Example() that are my own and don't necessarily represent the style of other C++ programmers. Related, there are other ways of doing this and my way might not even be the best.

There are a lack of comments, I would add them but I think they'd only get in the way, the code is simple enough to understand.

This all said, you obviously don't know much about C++ so stating C# is more productive, while it might even be true, is hard to take seriously coming from yourself. Also, some of the algorithms you do in C# might actually be really inefficient, like only storing the ID of the Tyre's bike, then doing a linear search for the matching Bike.

GMan
If anyone feels there is a better way or finds something wrong, feel free to edit.
GMan
Thanks - yep, normally we'd have a collection in a collection, just wanted to demonstrate joins in linq.
ng5000
Why do you need to sort the bike list before calling unique?
ng5000
Unique only removes elements that are adjacent. Sorting will put all the similar pointers (and therefore duplicates) next to each other, then unique will remove them, leaving only one copy of each unique pointer.
GMan
Do you really need to provide the == overload? Will C++ not perform a shallow comparrison anyway for all stack variables?
ng5000
Evan Teran
Once you've done that, you could make a simply "copy_if" like this: http://www.richelbilderbeek.nl/CppCopy_if.htm and that would make things a little easier to read/maintain.
Evan Teran
+1  A: 

I didn't want to edit the other answer since it seems sane enough, but there were a few minor things I would have done differently. So here's a slightly edited version of the other answer which tries a bit to have a little more code-reuse. Also, I feel that using heap allocated objects is a little more true to the original c#.

NOTE: to be fair, this omits all memory cleanup, but if smart pointers were used, it would be simple enough.

#include <algorithm>
#include <list>
#include <string>

namespace LinqTest {

    template<typename In, typename Out, typename Pred>
    Out copy_if(In first, In last, Out res, Pred Pr) {
     while (first != last){
     if (Pr(*first))
      *res++ = *first;
     ++first;
     }
     return res;
    }

    struct ColorMatch {
        ColorMatch(Color c) : colour(c) {
     }

     bool operator()(const Vehicle *v) {
      return v->Colour == colour;
     }

    private:
     Color colour;
    };

    struct IdMatch {
        IdMatch(int id) : Id(id) {
     }

     bool operator()(const Bike *v) {
      return v->Id == Id;
     }

    private:
     int Id;
    };

    // C++ does not specificy a standard GUI library.
    // This is a small hack to make the code work below.
    // In a real solution, one would probably have a real
    // Color class that stores the red, green, and blue
    // components of the colors and provides operations
    // to act upon colors.
    struct Color {
        static const int Red = 0;
        static const int Green = 1;
        static const int Blue = 2;

        Color() : value(0) {
        }

        Color(int color) : value(color) {
        }

        bool operator==(const Color& rhs) const {
      return value == rhs.value;
        }

        int value;
    };

    struct Vehicle {
        Vehicle() : Id(0) {
        }

        Vehicle(int id, Color colour) : Id(id), Colour(colour) {
        }

        bool operator==(const Vehicle& rhs) const {
      return Id == rhs.Id;
        }

        int Id;
        Color Colour;
    };

    struct Tyre {
        Tyre() : Id(0), BikeId(0), Size(0) {
        }

        Tyre(int id, int bikeId, int size, std::string brand) : Id(id), BikeId(bikeId), Size(size), Brand(brand) {
        }

        int Id;
        int BikeId;
        int Size;
        std::string Brand;
    };

    struct Car : public Vehicle {
        Car() {
        }

        Car(int id, Color colour) : Vehicle(id, colour) {
        }
    };

    struct Bike : public Vehicle {
        Bike(int id, Color colour) : Vehicle(id, colour) {
        }
    };

    class Example {
    // I put private up top to match yours, but most C++
    // programmers would prefer it on the bottom, justified
    // by the fact users of the class don't care or want
    // to see how the class works, they want to see how to
    // use it.
    private:
        std::list<Car *> cars;
        std::list<Tyre *> bikeTyres;
        std::list<Bike *> bikes;

    public:
        Example() {
                cars.push_back(new Car(0, Color::Red));
                cars.push_back(new Car(1, Color::Blue));
                cars.push_back(new Car(2, Color::Green));
                cars.push_back(new Car(3, Color::Green));

                bikeTyres.push_back(new Tyre(0, 0, 23, "TyreCo1"));
                bikeTyres.push_back(new Tyre(1, 0, 23, "TyreCo1"));
                bikeTyres.push_back(new Tyre(2, 1, 30, "TyreCo2"));
                bikeTyres.push_back(new Tyre(3, 1, 30, "TyreCo2"));
                bikeTyres.push_back(new Tyre(4, 2, 23, "TyreCo3"));
                bikeTyres.push_back(new Tyre(5, 2, 23, "TyreCo3"));

                bikes.push_back(new Bike(0, Color::Red));
                bikes.push_back(new Bike(1, Color::Blue));
                bikes.push_back(new Bike(2, Color::Green));
        }

        // I chose to return pointers to Vehicles to maintain any
        // polymorphic behavior, since from what I understand C#
        // would be returning references here.
        std::list<Vehicle*> FindVehiclesByColour(Color colour) {
      copy_if(cars.begin(), cars.end(), std::back_inserter(result), ColorMatch(colour));
      copy_if(bikes.begin(), bikes.end(), std::back_inserter(result), ColorMatch(colour));
      return result;
        }

        std::list<Bike*> FindBikesByTyreSize(int size) {
      typedef std::list<Tyre>::const_iterator tyre_iterator;

      std::list<Bike*> result;

      for (tyre_iterator tyreIter = bikeTyres.begin(); tyreIter != bikeTyres.end(); ++tyreIter) {
       if (tyreIter->Size == size) {
        copy_if(bikes.begin(), bikes.end(), std::back_inserter(result), IdMatch(bikeIter->Id));
       }
      }

      result.sort();
      result.unique();
      return result;
        }
    };
}
Evan Teran