Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #14745 > unrolled thread

Treat vector of SubClass as vector of SuperClass

Started byEd <edmacdonald555@gmail.com>
First post2012-03-04 12:27 -0800
Last post2012-03-07 14:47 +0000
Articles 3 — 3 participants

Back to article view | Back to comp.lang.c++


Contents

  Treat vector of SubClass as vector of SuperClass Ed <edmacdonald555@gmail.com> - 2012-03-04 12:27 -0800
    Re: Treat vector of SubClass as vector of SuperClass Ian Collins <ian-news@hotmail.com> - 2012-03-05 10:45 +1300
    Re: Treat vector of SubClass as vector of SuperClass Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-03-07 14:47 +0000

#14745 — Treat vector of SubClass as vector of SuperClass

FromEd <edmacdonald555@gmail.com>
Date2012-03-04 12:27 -0800
SubjectTreat vector of SubClass as vector of SuperClass
Message-ID<14817030.1224.1330892827650.JavaMail.geo-discussion-forums@vbgu10>
Let's say I to classes, SuperClass and SubClass (the latter a sub class of the former). I have a vector of SubClasses, but I want to pass them to an API method somewhere that requires a vector of SuperClasses. What is the easiest way for me to go about passing the vector<SubClass> I have on hand to the API method which requires a vector<SuperClass>?

The code I'm working on is a little to convoluted right now to past in, so I came up with what I believe to be an equivalent example in a much more simplified problem domain. In the example, I have a Greeter class that knows how to greet someone. There are specialized version of this class that know how to greet  males and females (MaleGreeter and FemaleGreeter respectively). My question is, how do I achieve what I am trying to achieve in the commented out line (it won't compile with this line uncommented):
greetAll(maleGreeters);

Please forgive me for compiling my code against Boost in this example. I don't have a C++ 11 compliant compiler yet. I believe the classes I'm using from boost are included in the new C++ 11 standard (I recognize that this list is for standard C++ questions only).

Anyway, here's the code (followed by a short explanation of the real problem I'm trying to solve):

#include <iostream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

using std::cout;           using std::endl;
using std::string;         using std::vector;
using boost::shared_ptr;   using boost::make_shared;

/*
 * Greeter
 */
class Greeter{
   public:
      Greeter(string ln);
      string greet();
      virtual string getFormalAddress(string lastName) = 0;
   protected:
      string lastName;
};

Greeter::Greeter(string ln){
   lastName = ln;
}

string Greeter::greet(){
   return "Hello " + getFormalAddress(lastName);
}

/*
 * MaleGreeter
 */
class MaleGreeter : public Greeter{
   public:
      MaleGreeter(string ln);
      string getFormalAddress(string lastName);
};

MaleGreeter::MaleGreeter(string ln) : Greeter(ln) {}

string MaleGreeter::getFormalAddress(string lastName){
   return "Mr. " + lastName;
}

/*
 * FemaleGreeter
 */
class FemaleGreeter : public Greeter{
   public:
      FemaleGreeter(string ln);
      string getFormalAddress(string lastName);
};

FemaleGreeter::FemaleGreeter(string ln) : Greeter(ln) {}

string FemaleGreeter::getFormalAddress(string lastName){
   return "Ms. " + lastName;
}

/*
 * greetAll()
 */
void greetAll(vector<shared_ptr<Greeter> > greeters);

void greetAll(vector<shared_ptr<Greeter> > greeters){
   for(  vector<shared_ptr<Greeter> >::iterator i = greeters.begin();
         i != greeters.end(); i++){
      cout << (*i)->greet() << endl;
   }
}

/*
 * main()
 */
int main(int argc, char** argv){
   //Example 1
   shared_ptr<Greeter> g = make_shared<MaleGreeter>(string("MacDonald"));
   cout << g->greet() << endl << endl;

   //Example 2
   vector<shared_ptr<Greeter> > greeters;
   greeters.push_back(make_shared<MaleGreeter>("Jones"));
   greeters.push_back(make_shared<FemaleGreeter>("Doe"));
   greeters.push_back(make_shared<MaleGreeter>("Smith"));
   greeters.push_back(make_shared<FemaleGreeter>("Johnson"));
   greetAll(greeters);
   cout << endl;

   //Example 3
   vector<shared_ptr<MaleGreeter> > maleGreeters;
   greeters.push_back(make_shared<MaleGreeter>("Jones"));
   greeters.push_back(make_shared<MaleGreeter>("Smith"));
   //How do I make this line work?
   //greetAll(maleGreeters);
}
// End of code

So, the real problem I'm trying to solve is that I'm trying to write a chess rules engine. In my code, I have a representation of a chess board in a Board class of my own making. The representation in the Board class of the actual board is a member variable of this type:
vector<vector<shared_ptr<Square> > >
where Square is another class of my making. Square extends a virtual class, AsciiRenderable. AsciiRenderables are passed to an AsciiRendering framework which I intend to have print the representation of the board out on the terminal.

In other words, I wish the framework to operate on things with this signature:
vector<vector<shared_ptr<AsciiRenderable> > >

and Ideally, I would like to have it believe that
vector<vector<shared_ptr<Square> > > ISA vector<vector<shared_ptr<AsciiRenderable> > >

As I write this, I do realize that the ISA relationship there cannot be true because you can add elements to the latter that cannot be elements of the former (anything that is AsciiRenderable yet not a Square). But is there a simple way to achieve what I seek?

Thanks,
Ed

[toc] | [next] | [standalone]


#14746

FromIan Collins <ian-news@hotmail.com>
Date2012-03-05 10:45 +1300
Message-ID<9ri637FadbU3@mid.individual.net>
In reply to#14745
On 03/ 5/12 09:27 AM, Ed wrote:

[please try and wrap lines!]

<snip>

> So, the real problem I'm trying to solve is that I'm trying to write a chess rules engine. In my code, I have a representation of a chess board in a Board class of my own making. The representation in the Board class of the actual board is a member variable of this type:
> vector<vector<shared_ptr<Square>  >  >
> where Square is another class of my making. Square extends a virtual class, AsciiRenderable. AsciiRenderables are passed to an AsciiRendering framework which I intend to have print the representation of the board out on the terminal.
>
> In other words, I wish the framework to operate on things with this signature:
> vector<vector<shared_ptr<AsciiRenderable>  >  >
>
> and Ideally, I would like to have it believe that
> vector<vector<shared_ptr<Square>  >  >  ISA vector<vector<shared_ptr<AsciiRenderable>  >  >
>
> As I write this, I do realize that the ISA relationship there cannot be true because you can add elements to the latter that cannot be elements of the former (anything that is AsciiRenderable yet not a Square). But is there a simple way to achieve what I seek?

One solution would be to derive your vector classes privately form 
std::vector:

#include <vector>
#include <tr1/memory>

struct AsciiRenderable {};
struct Square : AsciiRenderable {};

typedef std::tr1::shared_ptr<AsciiRenderable> Ptr;
typedef std::tr1::shared_ptr<Square>          SquarePtr;

struct Vector : private std::vector<Ptr>
{
   using std::vector<Ptr>::push_back;
};

struct SquareVector : Vector {};

void f( Vector& );

int main() {
   SquareVector v;

   v.push_back(SquarePtr(new Square));

   f(v);
}

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#14806

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2012-03-07 14:47 +0000
Message-ID<slrnjlet83.1ls.grahn+nntp@frailea.sa.invalid>
In reply to#14745
On Sun, 2012-03-04, Ed wrote:

> Let's say I to classes, SuperClass and SubClass (the latter a sub
> class of the former). I have a vector of SubClasses, but I want to
> pass them to an API method somewhere that requires a vector of
> SuperClasses. What is the easiest way for me to go about passing the
> vector<SubClass> I have on hand to the API method which requires a
> vector<SuperClass>?

(Please don't use overlong lines! I reformatted the above manually.)

...
> void greetAll(vector<shared_ptr<Greeter> > greeters){
>    for(  vector<shared_ptr<Greeter> >::iterator i = greeters.begin();
>          i != greeters.end(); i++){
>       cout << (*i)->greet() << endl;
>    }
> }
...

I don't know if you've considered it or if it's reasonable in your
real-world code, but how about using template functions? 

greetAll() could be templatized on an iterator type and take a (begin,
end) range. Or it could be templatized on a container type and take a
const container& parameter.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web