cpp access subclass object methods from function that requires superclass object - c++

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.

Related

Pointer to a Superclass object may serve as pointers to subclass objects. But can't call memeber functions of the subclass. why?

I am enrolled in a C++ course, where i have the following code snippet:
class Pet {
protected:
string name;
public:
Pet(string n)
{
name = n;
}
void run()
{
cout << name << ": I'm running" << endl;
}
};
class Dog : public Pet {
public:
Dog(string n) : Pet(n) {};
void make_sound()
{
cout << name << ": Woof! Woof!" << endl;
}
};
class Cat : public Pet {
public:
Cat(string n) : Pet(n) {};
void make_sound()
{
cout << name << ": Meow! Meow!" << endl;
}
};
int main()
{
Pet *a_pet1 = new Cat("Tom");
Pet *a_pet2 = new Dog("Spike");
a_pet1 -> run();
// 'a_pet1 -> make_sound();' is not allowed here!
a_pet2 -> run();
// 'a_pet2 -> make_sound();' is not allowed here!
}
I'm not able to figure out why this is invalid. Please suggest suitable references for this that have ample explanation about why this is happening.
In C++, the types and names of variables at any point is what the compiler permits itself to know.
Each line of code is checked against the types and names of variables in the current scope.
When you have a pointer to a base class, the type of the variable remains pointer to the base class. The actual object it is pointing at could be a derived class, but the variable remains a pointer to the base class.
Pet *a_pet1 = new Cat("Tom");
a_pet1 -> run();
// 'a_pet1 -> make_sound();' is not allowed here!
the type of a_pet1 is Pet*. It may be pointing at an actual Cat object, but that is not information that the type of a_pet1 has.
On the next line, you are using a_pet1. You can only use it in ways that are valid for a Pet pointer on this line. a_pet1->make_sound() is not a valid operation on a Pet pointer, because the Pet type does not have a make_sound method.
You could do this:
Cat *a_pet1 = new Cat("Tom");
a_pet1 -> run();
a_pet1 -> make_sound(); // it now works!
because we changed the type of a_pet1 from Pet* to Cat*. Now the compiler permits itself to know that a_pet1 is a Cat, so calling Cat methods is allowed.
If you don't want to change the type of a_pet1 (which is a reasonable request), that means you want to support make_sound on a Pet, you have to add it to the type Pet:
class Pet {
protected:
string name;
public:
Pet(string n)
{
name = n;
}
void make_sound();
void run()
{
cout << name << ": I'm running" << endl;
}
};
now, a_pet1->make_sound() will be allowed. It will attempt to call Pet::make_sound, which is not Dog::make_sound, and as we didn't provide a definition for Pet::make_sound, this will result in an error at link time.
If you want Pet::make_sound to dispatch to its derived methods, you have to tell the compiler this is what you want. C++ will write the dispatch code for you if you use the virtual keyword properly, like this:
class Pet {
protected:
string name;
public:
Pet(string n)
{
name = n;
}
virtual void make_sound() = 0;
void run()
{
cout << name << ": I'm running" << endl;
}
};
here I both made make_sound virtual, and made it pure virtual. Making it virtual means that the compiler adds information to each Pet and Pet derived object so, when it is actually pointing to a derived object type and not a Pet, the caller can find the right derived method.
Pure virtual (the =0) simply tells the compiler that the base class method Pet::make_sound intentionally has no implementation, which also means that nobody is allowed to create a Pet, or a even Pet derived object instance, without providing a make_sound implementation for its actual type.
Finally, note that I mentioned "permits itself to know". The compiler limits what it knows at certain phases of compilation. Your statement that a_pet1 is a Pet* tells the compiler "I don't want you to assume this is a Cat, even though I put a Cat in there". At later stages of compilation, the compiler can remember that fact. Even at runtime, it is sometimes possible to determine the actual type of an object (using RTTI). The forgetting of the type of the object is both intentional and limited.
It turns out that "forced forgetting" is quite useful in a number of software engineering problems.
There are other languages where all method calls to all objects go through a dynamic dispatch system, and you never know if an object can accept a method call except by trying it at runtime. In such a language, calling make_sound on any object whatsoever would compile, and at runtime it would either fail or not depending on if the object actually has a make_sound method. C++ intentionally does not do this. There are ways to gain this capability, but they are relatively esoteric.
In your example a_pet1 and a_pet2 are pointers to objects of the 'Pet' class so your compiler only allows you to access functions that are actually available in that class. The 'Pet' class iteself does not contain a 'make_sound' function in this case. To fix this problem you can define a 'make_sound' function in the base class and mark it as 'virtual'. This will make a function call over a base pointer always invoke the execution of the according function in the inheriting class.
class Pet {
protected:
string name;
public:
Pet(string n)
{
name = n;
}
void run()
{
cout << name << ": I'm running" << endl;
}
virtual void make_sound() {}
};
class Dog : public Pet {
public:
Dog(string n) : Pet(n) {};
void make_sound() override
{
cout << name << ": Woof! Woof!" << endl;
}
};
class Cat : public Pet {
public:
Cat(string n) : Pet(n) {};
void make_sound() override
{
cout << name << ": Meow! Meow!" << endl;
}
};
int main()
{
Pet* a_pet1 = new Cat("Tom");
Pet* a_pet2 = new Dog("Spike");
a_pet1->run();
a_pet1->make_sound();
a_pet2->run();
a_pet2->make_sound();
}

Subclass as argument in superclass's member function, C++

I'm new to OOP and I'm working on a C++ project. I isolated my problem to make answering easy but here's the real scenario:
I have a superclass member function, that modifies values inside the object that called it. The modification is based on a value coming from another object of the same class. This object is given to the function as the only parameter. Such as:
void BaseClass::function(BaseClass x) {}
However, I created a subclass. And if the parameter is a subclass type, I want to modify its unique attribute, too.
void BaseClass::function(DerivedClass x) {}
The problem is that the subclass is obviously defined later in the code.
I don't want it as two separate methods, because the calculation algorithm is already written inside, and also the solution I search for doesn't require to change the code at the places where the function is already in use. Besides, every other possibility that comes to mind (e.g. using typeid()) looks silly.
#include <iostream>
#include <string>
class Base
{
protected:
//common attribute
const std::string name;
public:
//constructor for common attribute
Base(const std::string nameString) : name(nameString) {}
//getter
std::string getName() { return name; }
//superclass as parameter
void test1(Base &example) { std::cout << example.getName(); }
//subclass as parameter (I'd want the line below to work)
//void test2(Derived &example) { std::cout << example.getNumber(); }
};
class Derived : private Base
{
protected:
//unique attribute
const std::string number;
public:
//constructor
Derived(const std::string nameString, const std::string numberString) : Base(nameString),
number(numberString) {}
//getter for unique attribute
std::string getNumber() { return number; }
};
int main ()
{
Base object = Base("whatever");
Base baseParameter = Base("base");
Derived derivedParameter = Derived("derived", "12");
object.test1(baseParameter);
//object.test2(derivedParameter);
return 0;
}
What is the standard way of doing it?
You could make test2 a template, and ensure that it's only used with types derived from Base:
template<typename Derived>
void test2(Derived &example)
{
static_assert(std::is_base_of_v<Base, Derived>);
std::cout << example.getNumber();
}
Here's a demo.

Why does an instance of a derived class call a method from the base class?

Please look at example 1 and example 2.
Example 1 differs from Example 2 only in the overridden method run() from ** class IA **
Question is written at the end.
Example 1:
#include <iostream>
class IA {
public:
void run() {
print();
}
void print() {
std::cout << "IA::print() \n";
}
};
class A : public IA {
public:
void print() {
std::cout << "A:: \n";
}
};
int main() {
A a1;
a1.run();
A * ptr = new A;
ptr->run();
}
This code prints:
IA::print()
IA::print()
Example 2:
#include <iostream>
class IA {
public:
void run() {
print();
}
void print() {
std::cout << "IA::print() \n";
}
};
class A : public IA {
public:
void run() {
print();
}
void print() {
std::cout << "A:: \n";
}
};
int main() {
A a1;
a1.run();
A * ptr = new A;
ptr->run();
}
This code prints:
A::
A::
Why does it print like that? What is the difference?
Thanks.
You chose not to make print virtual. That means no dynamic dispatch occurs. At any point you call the method, the local type information is used to determine which one you call.
void run() {
print();
}
so when you call a non-virtual print, whatever local print function that is seen from where run is written is called.
In IA::run, the only visible print is the IA::print. So IA::run calls IA::print.
In A::run you can see both IA::print and A::print; but the second hides the first. So A::print is called.
What the actual dynamic type of the object is does not matter, because you didn't ask for virtual dispatch. You asked for the function to be picked using local, static type information.
You can ask for virtual dispatch:
class IA {
public:
void run() {
print();
}
virtual void print() {
std::cout << "IA::print() \n";
}
};
I added the keyword virtual to print. And now the first version will call A:: version of print.
Some languages make all methods implicitly virtual. C++ does not, because there is some runtime overhead to virtual methods, and C++ tries not to make you pay for things you aren't using.
In the first program the member function run is a function of the base class. Within the function the static type of the pointe this is IA. The function print is searched in the class IA according to the static type of this.
In the second program the class A has the both functions run and print. They hide the corresponding functions of the class IA. So they are called
From the C++ Standard (13.2 Member name lookup)
1 Member name lookup determines the meaning of a name (id-expression)
in a class scope (6.3.7). Name lookup can result in an ambiguity, in
which case the program is ill-formed. For an id-expression, name
lookup begins in the class scope of this; for a qualified-id, name
lookup begins in the scope of the nested-name-specifier. Name lookup
takes place before access control (6.4, Clause 14).

C++ Inheritance: Do I have to repeat parent attributes in derived classes?

If I separate my classes into header/implementation files, is it possible to have inheritance without needing to redeclare inherited attributes in the child class?
Let me clarify with an example. Why is this allowed (taken from here):
#include <iostream>
using namespace std;
// Base class
class Shape {
public:
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// Derived class
class Rectangle: public Shape {
public:
int getArea() {
return (width * height);
}
};
int main(void) {
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
return 0;
}
But this isn't (try compiling here):
#include <string>
#include <iostream>
// HEADER FILE
class Person {
public:
virtual void speak() = 0;
protected:
std::string name;
std::string surname;
};
class Programmer : public Person {
public:
Programmer(std::string, std::string);
};
// CPP FILE
Programmer::Programmer(std::string name, std::string surname) :
name(name),
surname(surname)
{}
void Programmer::speak(){
std::cout << "My name is " + name + " " + surname + " and I like to code!";
}
I am not sure what is confusing. Member initializer list only allows to specify base class(es) or direct members of this class. Because of that, your second example is not compiling.
At the same time, derived classes have access to public and protected member of their base(s), so this is why first example is OK.
An interesting observation is that following code will compile:
Programmer::Programmer(std::string name_, std::string surname_) {
name = name_;
surname = surname_;
}
Note, this will mean name and surname will be first default-initialized (to empty strings) and than they will be assigned to the values passed in the Programmer constructor. This is efficiency loss, which might be very noticeable under certain circumstances.
The proper way of solving this idiomatically is buy giving Person a constructor which accepts two string arguments and initializes the members, and than calling this constructor from Programmer constructor.
In the Programmer constructor, in the initializer list the variables initialized can only be variables directly from that class or a base class constructor.
But in the body of the member functions/constructors inherited variables can be used, if they are effectively public or protected.

C++ inheriting member functions of the same type signature (shadowing)

// 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.