C++ equivalent of C# OOP if(Boy b is Student)

Viewed 147

I am trying to implement the system above using C++. Previously, I am using C# and OOP to do my programs, so this will be my first time using C++ and I know there is some differences between these two languages. What I am trying to do is I want to count number of voters in list of members from Logbook class.

In C#, i will use

foreach(Member m in _members) {
    if(Member m is Voter) {
        votercount++;
    }
}

However, i am not sure if in cpp, this implement is correct? In my Logbook.h file

class Logbook
{
private:
    std::list<Member> _members;

In my Logbook.cpp file:

int Logbook::CandidateCount() {
  int membercount;
  for(Member m: _members) {
    if (Member* m=dynamic_cast<const Member*>(&Candidate)) membercount++;
  }
  return membercount;
}

It display an error at &Candidate where it says identifier Candidate is undefined. Is it because Logbook class can't reach to Candidate class?

Any replies and help is very much appreciated.

3 Answers

There are a few things you are doing wrong here. First you are not initializing your counting variable so it will start off using some random value (it maybe zero or maybe something else).

Next you need to store pointers to the members of your list because in C++ polymorphism only works through pointers. If the list is responsible for deleting its elements (usual) then you should use a smart pointer like std::unique_ptr:

class Logbook {
public:
    int CandidateCount();

    // virtual destructor is (usually) important for polymorphic types
    virtual ~Logbook() = default;

    // store pointers in your list    
    std::list<std::unique_ptr<class Member>> members;
};

Then you can iterate through that list trying to dynamically cast each pointer to the type you want to count. If it returns a valid pointer then you know it is of that type. Otherwise a nullptr will be returned:

class Member: public Logbook {};
class Candidate: public Member {};
class Voter: public Member {};

int Logbook::CandidateCount()
{
    int membercount = 0; // initialize this!!!!

    for(auto& m : members) { // use reference here to avoid making a copy

        if(dynamic_cast<Candidate*>(m.get()))
            membercount++;
    }

    return membercount;
}

Note: If you want to do more than just count your candidates you can keep the pointer obtained from the dynamic cast like this:

class Candidate: public Member { public: void do_something(){} };

int Logbook::CandidateCount()
{
    int membercount = 0; // initialize this!!!!

    for(auto& m : members) { // use reference here to avoid making a copy

        if(auto c = dynamic_cast<Candidate*>(m.get())) {
            membercount++;

            // c is not nullptr and is type Candidate*    
            c->do_something(); // use your Candidate like this
        }
    }

    return membercount;
}
int Logbook::CandidateCount()
{
    int membercount{};
    for(auto const &m : _members) {
       if (dynamic_cast<Member*>(m))
           ++membercount;
    }
    return membercount;
}

I would try to avoid using RTTI and dynamic_casts in C++, and instead think of a way to implement what you're doing using a different approach, namely by exploiting the OOP nature of the language.

You already have two classes that both inherit from Member, so you could just add a CountMember(int& voterCount) method that lets each member log itself in. You then just call that method for each member you have. Something like this:

class Member {
public:
  virtual void countMember(int& voterCount) = 0;
};

class Candidate : public Member {
public:
  void countMember(int&) override {}
};

class Voter : public Member {
public:
  void countMember(int& voterCount) override {
    voterCount++;
  }
};

class Logbook {
private:
  std::list<Member> _members;
public:
  int CandidateCount() {
    int votercount = 0;
    for(auto& member : _members) {
      member.countMember(votercount);
    }
    return votercount;
  }
};

This makes it easy to add custom behaviors in the case new classes were to be added.

Related