2

I should specify that I'm a bit new to OOP. I'm tying to make a vector of type pointer to Person that has a method GetName() and access a method GetSpg() from my Player class that derives Person. I get an error "GetSpg() is not a member of Person". My question would be: is there any way to access both functions from the vector so that if it points to a Person to not show that method but if it is to do so?

Here is my code:

#ifndef _PERSON_H
#define _PERSON_H

#include <iostream>
#include <algorithm>

typedef std::pair<std::string, std::string> StrPair;

class Person :private StrPair
{

  public:
    Person(const std::string& fn = "none", const std::string& sn = "none")         :StrPair(fn,sn){};
    virtual void Update(const std::string& fn, const std::string& sn){ StrPair::first = fn; StrPair::second = sn; };
    virtual const StrPair& GetName(){ return (const StrPair&)(*this); };
};
#endif

typedef std::pair<int, int> IntPair;

class Jucator: public Person, private IntPair
{
    std::string tip;
    int spg;
    int average;

  public:
    Jucator(const std::string& fn = "none", const std::string& sn = "none", 
        const std::string& t = "", const int& _spg = 0, const int& _avr = 0, 
        const int& _g = 0, const int& _r = 0) :Person(fn, sn),tip(t),spg(_spg),average(_avr),IntPair(_g,_r){};
    virtual void Update(const std::string& fn, const std::string& sn, const std::string& t, const int& _spg, const int& _avr,
        const int& _g, const int& _r){
    Person::Update(fn, sn); tip = t; spg = _spg; average = _avr; IntPair::first = _g; IntPair::second = _r;
};

virtual const int& GetSpg(){ return spg; };
Martin G
  • 17,357
  • 9
  • 82
  • 98
user1831468
  • 45
  • 1
  • 6
  • You can never access derived class methods from base class pointers, but you can do the other way round – coder hacker May 06 '14 at 08:26
  • `class Jucator: public Person, private IntPair` where `typedef std::pair IntPair`. Inheriting from STL is worst than making a deal with the devil. – 101010 May 06 '14 at 08:28
  • I hope people don't downvote this as being 'too trivial'. I know from experience that a lot of people, especially coming from web technology to C++, find this a tad confusing. – Sharadh May 06 '14 at 08:29
  • @Sharadh I'm not sure whare the user is trying to accomplish, is he searching for a vector or his own class? Why can't polymorphism help here? I'm confused – Marco A. May 06 '14 at 08:32
  • @Marco I'm not sure either, from his code. From what he's saying, however, he needs to cast and use it. Polymorphism here (by which I mean having a stub implementation of GetSpg() in person which does nothing) seems contrived. We're polluting the base class with a completely unrelated function in one of the derived classes. I can't see where the vector OP refers to is being used. If OP can give explanation of his use case, maybe we could do better? – Sharadh May 06 '14 at 08:42

3 Answers3

4

You can't. A pointer of type Person can only be used to access data/addresses(functions) that are part of the Person object. The compiler simply has no way of knowing what all classes could be deriving from Person and hence which operations are legal.

Have a look at Dynamic casting. MSDN Reference | Tutorial

In brief:

Player* pPlayer = dynamic_cast<Player*>(pPerson);
if (pPlayer) {
  //Use the pointer like a player pointer
  //Note: You can only call player functions from pPlayer, not pPerson
} else {
  //Use the pointer like a person pointer
}

Note that this casting is a runtime operation. At compile time, the compiler sees you using the Player pointer to access Player code, which it is happy to allow!

Disclaimer: I found your code tough to follow, so consider this an answer to your question in text

Sharadh
  • 1,298
  • 9
  • 15
  • 1
    Dynamic typing/casting can be used only if the base class has at least one virtual function (and in that case it is recommended that the destructor is virtual). – lrineau May 06 '14 at 10:05
  • Agreed - I've never used it without a `virtual` so just learnt this. Please check here for more: http://stackoverflow.com/questions/2253168/dynamic-cast-and-static-cast-in-c Thanks @lrineau! – Sharadh May 06 '14 at 10:22
  • Thanks for your help. Dynamic casting did the job. I was really confused why I couldn't access that method. The tutorial from cplusplus.com was very useful. – user1831468 May 07 '14 at 10:45
2

The problem you're facing is very similar to the classic animal/cat/dog example. The basic idea is you have a base class - Animal - and two classes that derive from it - Cat and Dog.

class Animal {
    public:
    Animal() {}
    virtual ~Animal() {}
};

class Dog : public Animal {
    public:
    Dog() : Animal() {}

    void bark() { std::cout << "Woof" << std::endl; }

    ~Dog() {}
}

class Cat : public Animal() {
    public:
    Cat() : Animal() {}

    void meow() { std::cout << "Meow" << std::endl; }

    ~Cat() {}
}

Now, if you declare a Cat or a Dog object, it's pretty obvious that you can call either bark() or meow(); but if you declare an Animal object, there's no way of knowing whether it's a Cat or a Dog, so you can't call either method.

In your case, you have Person as the base class and Player as the derived. You may further derive Person and have a new class, NonPlayer, so that Person would play the same role as Animal, and Player and NonPlayer would be Cat and Dog respectively.

If you really need to access Player methods from pointers to Person objects, you need to cast the Person* to Player* before. However, you need to be sure before that the pointer inside is a Player*. If it isn't, you'll most likely get a compilation error.

aleris
  • 21
  • 1
  • 2
0

There are concepts of upcasting and downcasting which are essential to understand your problem. You can use the concept of dynimc_cast, this Link would be helpful to understand.

samairtimer
  • 826
  • 2
  • 12
  • 28