In C++, I am using polymorphic classes and friendship to make a basic 'friends group'. However, when I am trying to access the private age function of the class person, which is a friend of the class Boy, I cannot access it. What is the problem?
/* Polymorphic Classes and Class Friendship */
#include <iostream>
class Person{
public:
Person(char* name, int age) : Name(name), Age(age){}
char* Name;
virtual void Speak(void){
std::cout << "I am a person called " << Name << std::endl;
}
virtual ~Person(void){delete this;}
private:
int Age;
};
class Boy : public Person{
friend class Person;
public:
Boy(char* name, int age, Person* Friend) : Person(name, age), MyFriend(Friend){}
void Speak(void){
std::cout << "I am a boy called " << Name << ". My friend " << MyFriend->Name << "'s age is " << MyFriend->Age /* Error here */ << std::endl;
}
~Boy(void){delete this;}
private:
Person* MyFriend;
};
int main(void){
Person* John = new Person("John", 12);
Boy* James = new Boy("James", 14, John);
Boy* Keith = new Boy("Keith", 18, James);
John->Speak();
James->Speak();
John->~Person();
James->~Boy();
Keith->~Boy();
return (0);
}
technical problem:
c++ friendship is one-way.
try protected to give access to derived classes.
code review:
/* Polymorphic Classes and Class Friendship */
It's a good idea to avoid C /*…*/ multiline comments in C++, because they do not nest, and some/many programmers use them to comment out code for debugging.
Instead preferentially use C++ // (single-) line comments.
#include <iostream>
OK.
class Person{
public:
OK.
Person(char* name, int age) : Name(name), Age(age){}
The first argument should be char const*. Without the const you will, for example, not be able to pass a literal string, when using a C++11-conforming compiler.
char* Name;
The raw pointer here needs to match the constructor formal argument.
Effectively, the way that it's initialized as a simple copy of the constructor's pointer argument, it limits the lifetime of any Person instance to the lifetime of the actual argument.
A std::string is a far more flexible and unproblematic choice.
virtual void Speak(void){
std::cout << "I am a person called " << Name << std::endl;
}
Since this function is not const, it cannot be called on a const object.
Also, the void is C-ism, ungood in C++.
In C it says that this function does not take any arguments. In C++ that's unnecessary, i.e. that void is needless verbiage. Besides, C doesn't even have member functions.
virtual ~Person(void){delete this;}
Again, the void is ungood.
The delete this is extremely ungood in this context.
private:
int Age;
The only problem with this is failure to apply some naming convention for data members. For example, like age_ (note that the underscore then goes at the end), or like my_age or myAge.
};
OK.
class Boy : public Person{
OK.
friend class Person;
Meaningless, since class Person doesn't access anything from this class.
public:
Boy(char* name, int age, Person* Friend) : Person(name, age), MyFriend(Friend){}
Again, should be char const*. Or std::string const&.
void Speak(void){
std::cout << "I am a boy called " << Name << ". My friend " << MyFriend->Name << "'s age is " << MyFriend->Age /* Error here */ << std::endl;
}
Here, if the compiler supports it, do add an override in order to have the compiler check that you're really overriding a base class function, like void Speak() override {.
In other words, ditch the void which is needless C-ism verbiage, but do add the override, which is very useful.
~Boy(void){delete this;}
The void is ungood.
The delete this is extremely ungood in this context.
private:
Person* MyFriend;
As earlier, this again limits the lifetime of a Boy instance.
};
OK.
int main(void){
The void is ungood.
Person* John = new Person("John", 12);
Boy* James = new Boy("James", 14, John);
Boy* Keith = new Boy("Keith", 18, James);
John->Speak();
James->Speak();
John->~Person();
So far OK.
James->~Boy();
Keith->~Boy();
Don't ever call destructors explicitly. Well, a really good experienced programmer might do that when using placement new for allocation: it is in the language for a reason. But as a beginner, and even with a year or two professional experience, don't do that.
return (0);
Technically OK but unecessary. main returns 0 by default.
}
You have specified that Person is a friend to Boy, but you want Boy to be friend of Person. However there's no need to use friendship. Boy already inherits Person thus if you declare age as protected class Boy can see it.
Related
I'm a beginner with c++ :), I simplified my problem to this:
I have a class Person
class Person{
string name;}
And another class Student that inherits Person
class Student : public Person{
string schoolName;}
And then I have a class Library that must have a different comportement depending on the input
class Library{
void checkBeforeEntry(Person* p){
cout << "You must be a student to enter" << endl;}
void checkBeforeEntry(Student* s){
cout << "You can enter" << endl;}}
At some point in my programm I'm storing a person like that: Person* guy;
because at that point I don't know yet if he is a simple person or a student.
But due to that I'm "loosing" the information about the real type of the object and I have tried this:
Person *p = new Person();
Student *s = new Student();
Person *g = new Student();
lib.checkBeforeEntry(p);
lib.checkBeforeEntry(s);
lib.checkBeforeEntry(g);
The Output was:
You must be a student to enter
You can enter
You must be a student to enter
But I want the last statement to be "you can enter".
I used a bit of polymorphism before to adapt the comportement of the derived class but here I'm trying to change the comportement of a third party class (library) so the situation is not the same as I am used to. Do you know how to solve this or if I should use another design ?
You can use dynamic_cast to cast downwards which will only succeed (i.e return a non nullptr value) if the runtime type is correct.
Applied to your situation:
void checkBeforeEntry(Person* p){
if (dynamic_cast<Student*>(p)) {
std::cout << "You can enter" << std::endl;
} else {
std::cout << "Only students can enter" << std::endl;
}
}
This has the downside however, that it requires Runtime Type Information (RTTI) to be enabled and might be quite costly (as usual implementations look up and check RTTI informations stored right next to the vftable). Also it requires you to specify specific types (imagine how adding Professor, Librarian, etc. classes would bloat the above code)
An arguably better approach can be to declare a virtual bool isStudent() or virtual bool canEnterLibrary() on Person
What you are using here is called a static-polymorphism. Which means that the type checking is taking place at compile-time and not run-time. I.e. the type of the pointers is deciding the type of the objects and hence the version of the overloaded function checkBeforeEntry() to be called.
To achieve what you want, and in a simplest way with the minimal impact on the existing code you have, I think the following can be the best.
class Person {
public:
string name;
virtual bool passLibrary() const {return false;}
virtual ~Person();
};
class Student: public Person {
public:
string schoolName;
bool passLibrary() const override {return true;}
virtual ~Student();
};
class Library {
public:
void checkBeforeEntry(const Person *p) const {
if (p->passLibrary()) {
cout << "You can enter" << endl;
} else {
cout << "You must be a student to enter" << endl;
}
}
};
So here the function passLibrary() is a virtual function, which means it'll use the dynamic-polymorphism, i.e. check the current object type at run-time, and each of your classes Person and Student will provide their own implementation, which will be used by the class Library to distinguish easily between Person and Student objects.
I hope this was clear enough.
class Person {
string name;
public:
virtual ~Person() = default;
virtual bool isStudent() const { return false; }
};
class Student : public Person {
string schoolName;
public:
bool isStudent() const override { return true; }
};
class Library {
void checkBeforeEntry(Person* p) {
if (!p->isStudent())
cout << "You must be a student to enter" << endl;
else
cout << "You can enter" << endl;
}
};
I have written the following code:
// constructors and derived classes
#include <iostream>
using namespace std;
class Mother
{
public:
int age;
Mother()
{
cout << "Mother: no parameters: \n"
<< this->age << endl;
}
Mother(int a)
{
this->age = a;
}
void sayhello()
{
cout << "hello my name is clair";
}
};
class Daughter : public Mother
{
public:
int age;
Daughter(int a)
{
this->age = a * 2;
};
void sayhello()
{
cout << "hello my name is terry";
}
};
int greet(Mother m)
{
m.sayhello();
}
int main()
{
Daughter kelly(1);
Son bud(2);
greet(kelly);
}
and my question is this:
Since kelly is an instances of a class derived from Mother it makes sense to me that I can pass it into a function that requires an object of type mother ie. greet. My question is this, is it possible to call the sayhello function from within greet such that it will say
it will say "hello my name is terry" instead of "hello my name is clair".
What you're asking for is called "polymorphic behavior" (or "dynamic dispatch") and it is a basic feature of C++. To enable it, you'll need to do a couple of things:
Tag your sayhello() methods with the virtual keyword (i.e. virtual void sayhello() rather than just void sayhello())
Change the greet() method's argument to pass-by-reference or pass-by-pointer, to avoid object-slicing problems (i.e. int greet(const Mother & m) rather than int greet(Mother m))
Once you've done that, the compiler will intelligently choose which sayhello() method to call at run-time, based on the m argument's actual object-type, rather than hard-coding the choice at compile-time based on the type explicitly listed in the greet function's arguments-list.
I am having troubles wrapping my head around the use of static class variables, and what exactly to include within the main file, as opposed to the function file. When I try to compile my code I get a huge number of errors.
The question provided requires me to create a static ID variable that is incremented by each new animal (e.g. Elephant and Cheetah), so elephant would display ID 1 and cheetah ID 2. I know my animal.h file is correctly formatted, but I am unsure about the main and animal.cpp files.
Could someone please correct any issues that are present within my code? Thanks!
animal.h
#include <iostream>
#include <string>
using namespace std;
#ifndef ANIMAL_H
#define ANIMAL_H
class animal{
public:
animal();
animal(string aSpecies); //Animals are allocated a unique ID on
//creation,
//the first animal has ID 1, second is 2
//and so on
void set_name(string aName); //Change the animals name
string get_species();
string get_name();
std::string name;
std::string species;
int get_ID(); //The animals unique ID
static int currentID; //The next ID number to give out
~animal();
};
#endif //ANIMAL_H
animal.cpp
#include <iostream>
#include "animal.h"
using namespace std;
//static ID variable
int animal::currentID = 0 ;
//Default animal constructor implementation
animal::animal(){
name = "?";
currentID++;
}
animal::animal(string aSpecies){
species = aSpecies;
}
void animal::set_name(string aName){
name = aName;
}
std::string animal::get_species(){
return species;
}
std::string animal::get_name(){
return name;
}
main-1-1.cpp
#include <iostream>
#include "animal.h"
using namespace std;
int main(){
animal Elephant;
animal Cheetah;
Elephant.set_name("Katrina");
Cheetah.set_name("Alex");
cout << Elephant.get_name() << " " << animal::currentID <<endl;
cout << Cheetah.get_name() << " " << animal::currentID << endl;
return 0;
};
There is some syntax to correct
The static member variable has the classes namespace, so in main you also have to call it with
animal::currentID
Then, new returns a pointer, so Elephant and Cheetah should be declared like
animal* Elephant;
animal* Cheetah;
Elephant = new animal("Elephant");
Cheetah = new animal("Cheetah");
However, there is no reason to use pointers here, just do
animal Elephant("Elephant");
animal Cheetah("Cheetah");
Also, the default constructor has not been defined in the classes body, you have to add
animal();
to the class declaration.
The members name and species are missing in the class body, too so make sure to add
private:
std::string name, species;
to the class body
There is no << operator for animal yet, so the output does not know what to do. You can add them to the class or output only the species member of the animal. Overloading the operator would look like this
std::ostream& operator<<(std::ostream &os, animal const &A){
os << "The animal " << A.name << " is of species " << A.species
<< " and has ID " << A.myID;
};
And you typically declare it as a friend non-member, so add
friend std::ostream& operator<<(std::ostream &os, animal const &A);
to the class body, this allows the operator to access the private members of animal. Note that this requires <iostream> for animal to work. You can then do
std::cout << Cheetah << std::endl;
And it will print the description of Cheetah.
Some further advice:
Having using namespace in a header file is a dangerous thing, it might bring things into scope that you are not aware of.
From the code you posted, currentID has no reason to be a member of animal, it can just be a local variable in main. If you want to keep track automatically, you can add a non-static member myID and increment the ID upon construction like this
class animal{
public:
animal::animal():myID(++currentID){};
private:
static int currentID;
int myID`
};
int animal::currentID = 0;
It looks like you are declaring the static variable correctly and setting it to zero. However, you need to increment it in the constructors (animal::animal).
The other issue is that you are using the new keyword to allocate two animals on the heap, but then you are assigning the pointers to animal objects. Here are two ways you could handle this instead instead:
animal Elephant("Elephant"); // Not on the heap
OR
animal *Elephant = new animal("Elephant"); // Elephant is a pointer to an object on the heap
Another thing, std::cout has no way of knowing how to print these objects. Instead of printing them directly, you should call one of your get_ functions:
cout << "The animal " << Elephant.get_species() << ... ;
Finally, if you want to be able to access the ids of the animals, you need to store the ids as member variables and use the static id variable as an incremented to ensure that every animal has a unique, consecutive id.
// Shadowing
#include <iostream>
using namespace std;
const int MNAME = 30;
const int M = 13;
class Person { // Base Class
char person[MNAME+1];
public:
void set(const char* n);
void display(ostream&) const;
protected:
const char* name() const;
};
void Person::set(const char* n) {
strncpy(person, n, MNAME);
person[MNAME] = '\0';
}
void Person::display(ostream& os) const {
os << person << ' ';
}
const char* Person::name() const { return person; }
class Student : public Person { // Derived
int no;
char grade[M+1];
public:
Student();
Student(int, const char*);
void display(ostream&) const;
};
Student::Student() {
no = 0;
grade[0] = '\0';
}
Student::Student(int n, const char* g) {
// see p.61 for validation logic
no = n;
strcpy(grade, g);
}
void Student::display(ostream& os) const {
os << name() << ' '
<< no << << ' ' << grade << endl;
}
int main() {
Person person;
Student student(975, "ABBAD");
student.set("Harry");
student.display(cout); // Harry 975 ABBAD
person.set("Jane Doe");
person.display(cout); // Jane Doe
}
The first call to display() (on student) calls the Student version of
display(). The second call to display() (on person) calls the Person
version of display(). The derived version of display() shadows the
base version on the student object. The base version executes on the
person object.
I don't understand what shadowing is then. I realize that both classes have the same display function defined, and obviously if you call student.display and person.display its going to call them accordingly. So what does this mean:
The derived version of display() shadows the base version on the
student object. The base version executes on the person object.
I don't understand shadowing.
source: https://scs.senecac.on.ca/~btp200/pages/content/dfunc.html
Inheritance - Functions of a derived class
Your Student class inherits from Person. That means, among other things, that Student objects consist from all the internals defined in Student and from all the internals defined in Person - for this matter Student can be seen as containing the Person. This means that Student object contains both versions of display method - one from the the base class and one from the derived. Shadowing means that when invoking the display from the derived object, it will call the derived class version, and the base class version is "shadowed" by it and not called. You can call the shadowed version from within Student by explicitly specifying it with base class prefix: Person::display. In general, the function that will be called is the one closest in scope - for Derived objects it's the scope of Derived and functions residing in outer scopes (such as base) are shadowed away.
It means that you're most likely missing a virtual.
E.g., your Person class should probably look like:
class Person { // Base Class
char person[MNAME+1];
public:
void set(const char* n);
virtual void display(ostream&) const;
protected:
const char* name() const;
};
Right now, if you have the following code:
Person* student = new Student(975, "ABBAD")
student->set("Harry");
student->display(cout);
Your output will be "Harry " instead of "Harry 975 ABBAD\n". As icepack says, the reason you're getting the message is because the display method in the Student class "shadows" the display method in the Person class, and because you have not declared that method virtual, the compiler assumes that the shadowing is accidental. If it's not accidental, then you should declare that method virtual.
Try this little experiment. Define the following function:
void person_display(Person &p){
p.display(cout);
}
Then have main call it on person and student.
int main(){
// [...]
person_display(person);
person_display(student);
}
You will see that in both cases, the method Person::display will be called. The shadowing is a phenomenom happening because of the redefinition in a class of a method of its ancestor class. It shadows the previous definition, as long as the instance is considered as the subclass, but as soon as it is seen as the ancestor, the shadowing disappears.
This is in contrast with a virtual method, where the method called is always the one defined in the real instance class, ie. in the experiment described above, you would see the Student method being called, even though it is seen as a simple Person.
Can anyone explain the output of the following code?
#include <iostream>
#include <string>
class Animal
{
public:
Animal(const std::string & name) : _name(name) { }
~Animal() { }
virtual void printMessage() const
{
std::cout << "Hello, I'm " << _name << std::endl;
}
private:
std::string _name;
// other operators and stuff
};
class Cow : public Animal
{
public:
Cow(const std::string & name) : Animal(name) { }
~Cow() { }
virtual void printMessage()
{
Animal::printMessage();
std::cout << "and moo " << std::endl;
}
};
int main() {
Cow cow("bill");
Animal * animal = &cow;
cow.printMessage();
animal->printMessage();
}
The output is
Hello, I'm bill
and moo
Hello, I'm bill
I don't understand why. The pointer animal points at an object of type Cow. printMessage is a virtual function. Why isn't the implementation of the Cow class the one that is called?
Cow isn't overriding the virtual function from Animal because it has a different signature. What's actually happening is that Cow is hiding the function in Animal.
The result of this is that calling printMessage on an Animal will just use the version in Animal, regardless of the one in Cow (it isn't overriding it), but calling it from Cow will use the one in Cow (because it hides the one from Animal).
To fix this, remove the const in Animal, or add the const in Cow.
In C++ 2011, you will be able to use the override keyword to avoid subtle traps like this:
class Cow : public Animal
{
public:
Cow(const std::string & name) : Animal(name) { }
~Cow() { }
virtual void printMessage() override
{
Animal::printMessage();
std::cout << "and moo " << std::endl;
}
};
Notice the added override after printMessage(). This will cause the compiler to emit an error if printMessage doesn't actually override a base class version. In this case, you would get the error.
You have two different versions of printMessage, one which is const and one which isn't. The two are unrelated, even though they have the same name. The new function in Cow hides the one in Animal, so when you call it directly the compiler only considers the Cow version.
It took me a while to understand Peter Alexander's hiding answer, but another way to understand it is as follows:
Say that you mispelled the method name in the Cow class, but spelled it correctly in Animal class:
Animal::printMessage()
Cow::mispelledPrintMessage()
then when you have an
Animal *animal;
you can ONLY call
animal->printMessage();
but you CANNOT call
animal->mispelledPrintMessage();
because mispelledPrintMessage() doesn't exist in the Animal class. Its a brand new method in the Cow class, so it cannot be polymorphically called thru a base pointer.
So having the Animal method have const in the signature, but not in Cow method is kinda analogous to a slightly mispelled method name in the derived class.
PS: Another 4th solution (1 making both methods const, 2 making both methods non-const, or 3 using new 2011 override keyword), is to use a cast, to force the Animal pointer into a Cow pointer:
((Cow*)animal)->printMessage();
But this is a very ugly HACK, and I would not recommend it.
PS: I always try to write my toString() methods with const in the signature in the Base class and all derived classes for this very reason. Plus, having const in the toString() signature allows you call toString() either with a const or non-const object. Had you instead left out the const, and tried to pass call toString() with a const object, GCC compiler would complain with the discards qualifiers error message:
const Bad' as `this' argument of `std::string Bad::toString()' discards qualifiers
for this code:
#include <iostream>
#include <string>
class Bad
{
public:
std::string toString()
{
return "";
}
};
int main()
{
const Bad bad;
std::cout << bad.toString() << "\n";
return 0;
}
So, in conclusion, since Cow doesn't change any data members, the best solution probably is to add const to printMessage() in derived Cow class, so that both BASE Animal and DERIVED Cow classes have const in their signatures.
-dennis bednar
-ahd 310
Correction to Dennis's post.
Note you state as a solution you can cast the animal (which is a Animal*) to a Cow*. However, once a Cow* your printMessage from the Animal class will not be available.
Therefore ((Cow*)animal)->printMessage() needs to be ((Cow*)animal)->mispelledPrintMessage()
Just tried it. Add the const to the Cow class and it will work.
i.e. virtual void printMessage () const for both classes.
virtual in subclass-->no need. You just add const to function in subclass to make it same signature