Accessing derived class members with a base class pointer - c++

I am making a simple console game in C++
I would like to know if I can access members from the 'entPlayer' class while using a pointer that is pointing to the base class ( 'Entity' ):
class Entity {
public:
void setId(int id) { Id = id; }
int getId() { return Id; }
protected:
int Id;
};
class entPlayer : public Entity {
string Name;
public:
void setName(string name) { Name = name; }
string getName() { return Name; }
};
Entity *createEntity(string Type) {
Entity *Ent = NULL;
if (Type == "player") {
Ent = new entPlayer;
}
return Ent;
}
void main() {
Entity *ply = createEntity("player");
ply->setName("Test");
ply->setId(1);
cout << ply->getName() << endl;
cout << ply->getId() << endl;
delete ply;
}
How would I be able to call ply->setName etc?
OR
If it's not possible that way, what would be a better way?

It is possible by using a cast. If you know for a fact that the base class pointer points to an object of the derived class, you can use static_cast:
Entity* e = /* a pointer to an entPlayer object */;
entPlayer* p = static_cast<entPlayer*>(e);
p->setName("Test");
If you don't know for sure, then you need to use dynamic_cast and test the result to see that it is not null. Note that you can only use dynamic_cast if the base class has at least one virtual function. An example:
Entity* e = /* a pointer to some entity */;
entPlayer* p = dynamic_cast<entPlayer*>(e);
if (p)
{
p->setName("Test");
}
That said, it would be far better to encapsulate your class's functionality using polymorphism (i.e. virtual functions).
Speaking of virtual functions, your class hierarchy as implement has undefined behavior: you can only delete an object of a derived type through a pointer to one of its base classes if the base class as a virtual destructor. So, you need to add a virtual destructor to the base class.

I would consider doing something like this:
public:
void setId(int id)
{
Id = id;
}
void virtual setName( string name ) = 0; // Virtual Function
string virtual getName() = 0; // Virtual Function
int getId() { return Id; }
protected:
int Id;
};
class entPlayer : public Entity {
string Name;
public:
entPlayer() {
Name = "";
Id = 0;
}
void entPlayer::setName(string name) { // Must define function
Name = name;
}
string entPlayer::getName() { return Name; } // again must define function here
};

You can do a dynamic cast:
entPlayer * pPlayer = dynamic_cast<entPlayer *>(pointer_to_base);
This will (if successful) result in a derived pointer.
Otherwise NULL is returned.

C++ makes what you are trying to do really awkward, because this is probably not what you should be doing, and it is trying to lead you to good object-oriented design. In fact, by default, compilers often disable run-time type information (RTTI), which is needed to make dynamic_cast work.
Without knowing your broader context, it's hard to say what you should do instead. What I can say is that if you wanted a more specific pointer, you should have put a ring on it you almost certainly shouldn't use a function that returns an Entity*, and there is probably a better approach.

Related

Access function from another class without having any relations

I'm still new to C++ and I'm trying to know if it is possible to access a function from another class knowing that no one is the father class here . This is a piece of my program to show you what I want to do exactly .
class CSubject
{
public:
CSubject() = default;
CSubject(std::string m_Name){this->Name = m_Name;}
void print(){ std::cout << Name;}
~CSubject(){}
private:
std::string Name;
};
class CStudent
{
public:
CStudent() = default;
void Method2()
{
//Call the print method and print the name "test"
}
~CStudent(){}
private:
};
int main()
{
CSubject AE("test");
CStudent ST;
ST.Method2(); //Print test;
return 0;
}
Forget about classes for a second. You want to call Method2(), and from there, print information that was put into the AE. Suppose you didn't have two classes of your own, but rather, say:
void Method2();
int main() {
const char* AE = "Test";
// ...
Method2();
}
That wouldn't work, right? And it shouldn't work, because local variables in a function (like main()) are usable only within that function's body; that's their local scope. For Method2() to use AE in any way, you have to let Method2() "know" about it. It's the same with classes.
You could use static method and attributes, which can be altered by creating an instance and overwriting it and also getting them from unrelated processes.
I would edit your CSubject class like this:
class CSubject {
public:
CSubject() = default;
CSubject(std::string m_Name) {
CSubject::Name = m_Name;
}
static void print() {
if (CSubject::Name.empty()) //checking is a good practice
std::cout << "The name is empty...\n";
else
std::cout << Name;
}
~CSubject() {}
private:
static std::string Name;
};
And you could access the print method from your Method2 like this:
void Method2() {
CSubject::print();
}
But beware! The static attribute is the only one for the class. If you plan on creating multiple CSubject instances and their new names, then you could store the m_Name attribute as non-static private, print() as non-static public, and Method2 should have a parameter where you pass the CSubject (the whole object or just the data that you need) that is in your interest.

C++ array of the same class hierarchy

According to my book, if I want to make an array of objects that are not in the same class but in the same class hierarchy, I need to use pointers:
class text
{
public:
void write(string text);
void show();
private:
string texte;
};
void text::write(string text)
{
texte = text;
}
void text::show()
{
cout << texte;
}
class text_with_stars : public text
{
public:
void show();
};
void text_with_stars::show()
{
cout << "*";
text::show();
cout << "*";
}
int main()
{
text* array[2];
array[0] = new text;
array[0]->write("Hello");
text_with_stars* pointer = new text_with_stars;
pointer->write("Hi");
array[1] = pointer;
for (int i=0;i<2;i++)
{
array[i]->show();
}
return 0;
}
But when I do this, the output is "HelloHi" meaning that the second object used the show version that is from text and not from text_with_stars, but I made it exactly the same way that the book described. What Is the problem??
Here is what is written in the book:
Question* quiz[2];
quiz[0] = new Question;
quiz[0]->set_text("Who was the inventor of C++?");
quiz[0]->set_answer("Bjarne Stroustrup");
ChoiceQuestion* cq_pointer = new ChoiceQuestion;
cq_pointer->set_text("In which country was the inventor of C++ born?")
cq_pointer->add_choice("Australia",false);
...
quiz[1] = cq_pointer;
The chapter right next to the one I was reading is about virtual functions and it explains that the system will always use the member functions of Question instead of ChoiceQuestion, looks like I should read more before asking questions on internet!
void show()
needs to be virtual in the base class if you want to use methods from derived classes from base class pointers
The reason this is happening is because the function you are calling is non-virtual.
Let's say we have a class Parent and a class Child inheriting from the parent:
class Parent {
public:
void f() {
cout << "Parent::f()" << endl;
}
};
class Child : public Parent {
public:
void f() {
cout << "Child::f()" << endl;
}
};
Now, let's make a pointer to a Parent and store a Child in it (polymorphism):
Parent *ptr = new Child;
ptr->f();
At this point, the compiler sees ptr having type Parent* and determines that the function to be called is Parent::f().
In order to call Child::f() when dealing with polymorphism? The Parent::f() must be defined virtual. The compiler then generates code to check at run-time the value that is stored in memory to call the appropriate (child) function.
In short: ONLY when a function is virtual and is called on a pointer or reference, a memory lookup is made to determine the actual type at that point in memory. Otherwise it is not.

Memory sharing; Inheritance; Base and Derived instances; C++

Ok, this example is pretty straight-forward for the concept I'm trying to understand. I'll just show you the code:
class Base
{
protected:
string name;
public:
virtual string getName() const { return this->name; }
virtual void setName(string name) { this->name = name; }
....
}
class Derived : public Base
{
private:
double price;
....
}
main(int argc, char** argv)
{
Base* base = new Base("Base Class");
Derived* derived = new Derived(base, 453.21);
derived->setName("Name changed!");
cout << "Name of instance: " << base->getName() << endl;
// Desired effect
Output: 'Name changed!'
// Actual effect
Output: 'Base Class'
....
}
The issue for me is this. I want to create an instance of derived class with reference to already created instance of base class, so when I change any member variable of base class trough the derived instance, I can see the change on previously created base instance in the way demonstrated above.
Note: I hope that you will manage to comprehend what I meant, as I am aware that my terminology is probably little off. Please, don't be harsh. :)
Note: I won't be showing / writing constructors, since I am not sure what is the best way to do this, if even any exists and the syntax may be incorrect.
This seems to indicate the problem:
Base* base = new Base("Base Class");
Derived* derived = new Derived(base, 453.21);
as it is usually not necessary to construct the Base class separatly. Your derived class will already contain a Base instance implicitly, you don't have to add a pointer to one manually and set it from the ctor. I don't know how your ctor looks, but it should look like this:
Derived(const std::string& name, double p) : Base(name), price( p ) {}
If this enough to fix it yourself, good, otherwise post all the code of your example. Instead of the two lines from your code that I quoted above, it should look more like:
Derived* derived = new Derived("Base Class", 453.21);
If you post the code of Derived, it should be obvious for us and it will be much easier to explain it to you on your concrete example.
The way you are trying to do is weird, but you can simply use inheritance concept like this code:
class Base
{
public:
Base(const string &name) : name(name) {}
virtual void setName(const string &name) { this->name = name; }
virtual string getName() const { return name; }
protected:
string name;
};
class Derived : public Base
{
public:
Derived(const string &name, double price) : Base(name), price(price) {}
private:
double price;
};
int main()
{
Derived* derived = new Derived("Base Class", 453.21);
derived->setName("Name changed!");
Base *base = derived;
cout << "Name of instance: " << base->getName() << endl;
}
Output
Name of instance: Name changed!
You don't need a create Base object and pass it to the derived object.
Instead, create a derived object and pass its address to a Base pointer.

Defining two classes inside a class, and accessing its members

I'm trying to access members of a classC from classB, both classC and classB are inside classA. Here is what I'm trying to do;
//hello.h
class hello{
public:
hello();
class letters{
public:
letters();
void setName(char n);
char getName();
private:
char name;
}
class sayHi{
public:
sayHi();
void onJoin();
}
}
//hello.cpp
hello::hello(){}
hello::letters(){}
hello::sayHi(){}
void hello::letters::setName(char n){
hello::letters::name = n; //trying to access the private variable 'name' inside class letters
}
char hello::letters::getName(){
return hello::letters::name = n;
}
void hello::sayHi::onJoin(){
cout<< hello::letters::getName() <<endl;
}
I know i'm doing it wrong, am I supposed to create instances of each class and call the members?
Yes, you're supposed to create instances of the classes.
These are frequently called "objects", which is why they call it "object-oriented programming".
First, your getName and setName should look like this:
void hello::letters::setName(char n) {
name = n;
}
char hello::letters::getName() const { // Declaration should also say "const".
return name;
}
With that out of the way, any sayHi instance needs to know which letters to say "Hi" to, which means that you need to tell it.
This is usually done by passing a parameter to the method that needs to know:
class sayHi{
public:
sayHi();
void onJoin(const letters& who)
{
cout << who.getName() << endl;
}
};
which you would use somewhat like this:
int main()
{
hello::letters letter;
letter.setName('p');
hello::sayHi greeter;
greeter.onJoin(letter);
}
What is the error you are getting ? where have you created objects for accessing these methods ? Also
return hello::letters::name = n;
this line is wrong, it should be
return hello::letters::name;

Changing type of object in a conditional

I'm having a bit of trouble with dynamic_casting. I need to determine at runtime the type of an object. Here is a demo:
#include <iostream>
#include <string>
class PersonClass
{
public:
std::string Name;
virtual void test(){}; //it is annoying that this has to be here...
};
class LawyerClass : public PersonClass
{
public:
void GoToCourt(){};
};
class DoctorClass : public PersonClass
{
public:
void GoToSurgery(){};
};
int main(int argc, char *argv[])
{
PersonClass* person = new PersonClass;
if(true)
{
person = dynamic_cast<LawyerClass*>(person);
}
else
{
person = dynamic_cast<DoctorClass*>(person);
}
person->GoToCourt();
return 0;
}
I would like to do the above. The only legal way I found to do it is to define all of the objects before hand:
PersonClass* person = new PersonClass;
LawyerClass* lawyer;
DoctorClass* doctor;
if(true)
{
lawyer = dynamic_cast<LawyerClass*>(person);
}
else
{
doctor = dynamic_cast<DoctorClass*>(person);
}
if(true)
{
lawyer->GoToCourt();
}
The main problem with this (besides having to define a bunch of objects that won't be use) is that I have to change the name of the 'person' variable. Is there a better way?
(I am not allowed to change any of the classes (Person, Lawyer, or Doctor) because they are part of a library that people who will use my code have and won't want to change).
Thanks,
Dave
Dynamic casting to a subclass and then assigning the result to a pointer to superclass is of no use - you practically are back where you started. You do need a pointer to a subclass to store the result of the dynamic cast. Also, if the concrete type of your object is PersonClass, you can't downcast it to a subclass. Dynamic casting can only work for you if you have a pointer to a superclass but you know that the object pointed to is actually an instance of a subclass.
As others have pointed out too, the best option would be to redesign the class hierarchy to make your methods really polymorphic, thus eliminate the need for downcasting. Since you can't touch those classes, you need the downcast. The typical way to use this would be something like
PersonClass* person = // get a Person reference somehow
if(/* person is instance of LawyerClass */)
{
LawyerClass* lawyer = dynamic_cast<LawyerClass*>(person);
lawyer->GoToCourt();
}
else
{
DoctorClass* doctor = dynamic_cast<DoctorClass*>(person);
doctor->GoToSurgery();
}
Update: if you want to use the subclass instances later, you can do it this way:
PersonClass* person = // get a Person reference somehow
...
LawyerClass* lawyer = NULL;
DoctorClass* doctor = NULL;
if(/* person is instance of LawyerClass */)
{
lawyer = dynamic_cast<LawyerClass*>(person);
}
else if(/* person is instance of DoctorClass */)
{
doctor = dynamic_cast<DoctorClass*>(person);
}
...
if(lawyer)
{
lawyer->GoToCourt();
}
else if (doctor)
{
doctor->GoToSurgery();
}
Note that this code is more complicated and more error-prone than the previous version. I would definitely try to refactor such code to make it look more like the previous version. YMMV.
If they are not polymorphic functions (as David's answer defined them to be), then doing this is going to be more than difficult.
I would suggest a wrapper class.
class PersonWrapper {
PersonClass* person;
virtual void DoWork() = 0;
};
class DoctorWrapper : public PersonWrapper {
DoctorClass* doc;
virtual void DoWork() { doc->GoToSurgery(); }
};
class LawyerWrapper : public PersonWrapper {
LawyerClass* lawyer;
virtual void DoWork() { lawyer->GoToCourt(); }
};
Of course, this leaves some implementation details to be defined by you, such as assigning the pointer in correct conditions, and is an ugly use of heap. However, it should offer polymorphic functionality, in that you could now do
PersonWrapper* wrap = new LawyerWrapper(new LawyerClass());
wrap->DoWork();
I would only consider using this sort of solution if you're genuinely desperate.
I may be completely missing the point here or I may be misunderstanding you example so if I am let me know and I will delete my post.
But would it not make more sense to have a public method called doJob (or something similar) that calls the virtual method. That way you could do this:
#include <iostream>
#include <string>
using namespace std;
class PersonClass
{
public:
std::string Name;
virtual void doWork(){}; //it is annoying that this has to be here...
};
class LawyerClass : public PersonClass
{
public:
void doWork(){GoToCourt();}
void GoToCourt(){cout<<"Going to court..."<<endl;}
};
class DoctorClass : public PersonClass
{
public:
void doWork(){GoToSurgery();}
void GoToSurgery(){cout<<"Doing surgery..."<<endl;};
};
int main(int argc, char *argv[])
{
PersonClass* person;
if(true)
{
person = new LawyerClass();
}
else
{
person = new DoctorClass();
}
person->doWork();
return 0;
}
Is it possible for you to add a shim to the classes like this:
class Person
{
public:
virtual void DoJob() = 0;
};
class Lawyer : public Person, public LawyerClass
{
public:
virtual void DoJob() { GoToCourt(); }
};
class Doctor : public Person, public DoctorClass
{
public:
virtual void DoJob() { GoToSurgery(); }
};
void DoJob(Person& person)
{
person.DoJob();
}
int main(int argc, char *argv[])
{
Doctor doctor;
Lawyer lawyer;
DoJob(doctor); // Calls GoToSurgery();
DoJob(lawyer); // Calls GoToCourt();
return 0;
}
This way, you won't have to use a conditional. But this really is a "last-resort" solution if you really can't change the existing library code, and it does require your users to use Doctor and Lawyer instead of DoctorClass and LawyerClass.
dynamic_cast allows you to obtain a more precisely-typed reference or pointer to an object of a given type.
It does not allow you to change the type of the object. The type of a constructed object cannot change in C++. You must construct a new object.
LawyerClass lawyer( person );
EDIT: to adapt your sample into a rough demo of polymorphism,
PersonClass* person = NULL;
if(true)
{
person = new LawyerClass;
}
else
{
person = new DoctorClass;
}
if ( LawyerClass *lawyer = dynamic_cast< LawyerClass * >( person ) )
{
lawyer->GoToCourt();
}
Also, you should use an "empty" virtual destructor rather than virtual void test() {}.