2

I am learning about polymorphism in C++ and am learning about the virtual function specifier. Since the virtual specifier forces the program to use the child class's functions, why does it not force the function to use the child class's member variables? Is there a way to do this in C++?

I have tried running the following code with the following classes:

class Student
{
public:
    virtual int returnGPA()
    {
        return gpa;
    }
private:
    int gpa = 3;
};

class HonorStudent : public Student
{
public:
    virtual int returnGPA() override
    {
        return gpa;
    }

private:
    int gpa = 4;

};

int main()
{

    Student s = Student();
    Student h = HonorStudent();
    std::cout << s.returnGPA() << std::endl;
    std::cout << h.returnGPA() << std::endl;
    return 0;

}

I expected the output of the function to be

3
4

but the function outputs

3
3

When I change the declaration of h to be

HonorStudent h = HonorStudent();

the programs outputs what I initially expected. Any insight would be greatly appreciated.

uglygod
  • 61
  • 5
  • This is called slicing. After `Student h = HonorStudent();`, `h` is just a plain `Student`. – L. F. Jun 07 '19 at 04:19
  • You can try `protected:` variables instead of private and see if that helps. However, It's still not a good idea to make variables that have the same name as the parent, as a general rule. –  Jun 07 '19 at 04:21
  • Thank you @L.F. I was aware of the concept of slicing but was unaware that slicing extended to member variables of the same name. – uglygod Jun 07 '19 at 04:33
  • @Chipster I tried making the member variables both `protected` and `public`, but both still yielded the same results as above. Thank you for the advice about not having member variables with the same name as the parent, though! – uglygod Jun 07 '19 at 04:38
  • Do you by chance come from a Java background? – curiousguy Jun 07 '19 at 04:49
  • @curiousguy yes I do. I've programmed predominately in Java and Python. – uglygod Jun 07 '19 at 04:57
  • C++ syntax is different. You need to use pointers to have something similar to the semantics of Java references. **C++ class objects work like Java builtin types**: in C++ user defined types are treated as much as builtin types as possible. Java uses the same syntax for assigning (or initializing) a scalar value or a reference. There is no direct equivalent of these references in C++, but pointers come close (they can be changed and can be null). – curiousguy Jun 07 '19 at 05:04
  • Overriding `returnGPA()` seems conceptually wrong. You don't want make that kind of functions a customization point, and you don't have to have such useless state in base classes in proper OOP design. Why don't you start with a pure interface? Why do you put in your base class **an implementation detail that you want to inhibit in a derived class**? – curiousguy Jun 07 '19 at 05:15
  • "_but was unaware that slicing extended to member variables of the same name._" It does not. In fact, I have no idea what this could mean: "the concept of slicing extends to member variables for the same name"; or even "the concept of slicing extends to member variables". Slicing has to do with the copy operation (copy construction or assignment) **as defined by the member functions of the class**. Can you describe what you believed a copy constructor would do exactly? – curiousguy Jun 07 '19 at 05:17
  • @Chipster "_You can try protected: variables instead of private and see if that helps_" No. Just no. It does not make sense. Access control is orthogonal to name lookup (visibility of names) and has no relevance here. – curiousguy Jun 07 '19 at 05:18
  • 1
    @curiousguy my point is that if you need to access a data member of the parent in the child, then the member needs to be protected. It is an alternative to making a duplicate named variable and would potentially solve the issue, provided the OP got rid of the child data member. I guess I should have been more specific. –  Jun 07 '19 at 05:33
  • @curiousguy I only overrode `returnGPA()` because I was experimenting with the `virtual` specifier; this was not a program I intended to use anywhere (and I was aware of how redundant it was). I simply discovered this behavior and was curious as to why it occurred. I also have a rather rudimentary understanding of slicing because I have just learned about it. As per my understanding, a copy constructor copies the attributes of one instance of an object to another during assignment. How exactly does slicing use the copy constructor? – uglygod Jun 07 '19 at 09:47
  • @uglygod Careful here: assignment applies to an **existing** instance; copy construction creates an instance. A constructor doesn't change an existing instance. – curiousguy Jun 07 '19 at 16:28

0 Answers0