There is the following code:

#include <iostream> class Base { public: char val = 'a'; virtual char GetVal() { return val; } } class Derived : public Base { public: char val = 'A'; virtual char GetVal() { return val; } } int main() { Base *pb = Derived; std::cout << pb->val << std::endl; //Выведет: a std::cout << pb->GetVal() << std::endl; //Выведет: A delete pb; return 0; } 

From this code, you can see that the member with the identifier val of the base class Base is replaced with another member with the same identifier val in the derived class Derived .

In client code, when using a Base * type pointer that points to an object of type Derived , we can get access to the public val member of the derived class Derived only when using the virtual function GetVal () , which returns the value of this member.

  1. Is there any other way to access a member with the name val of a derived class that replaces the name of a base class member using a pointer to the base type without resorting to virtual get- replace functions ?

This is interesting because if the base class code is replaced with the following:

 class Derived : public Base { public: int val = 65; // был тип char - стал int virtual int GetVal() { // теперь возвращаем объект типа int return val; } } 

Then an error occurs at the compilation stage " conflicting return type specified for virtual int Derived :: GetVal () ' ", because when overriding a virtual function of a base class, the type it returns must be the same in a derived class.

  1. How can I get access to a member of a derived class whose name overlaps the name of a member of the base class, but has a different type, while operating with the pointers of the base class?

    5 answers 5

    way to access a member with the name val of a derived class, replacing the name of the base class member

    Bringing anyway required. Those. you need to know the name (or the location of the data) of the derived class:

     dynamic_cast<Derived*>(pb)->val; // A 

    In an amicable way, you still need to check the result dynamic_cast and on nullptr .

    You can also static_cast , if you are confident that pb points to an instance of a derived class:

     static_cast<Derived*>(pb)->val; // A 

    get access to a member of a derived class whose name overlaps the name of a member of the base class, but has a different type

    Exactly the same ways as I showed above.

      way to access a member ... derived class ... using a pointer to the base type

      The base type knows nothing about the derived class except the virtual function table.

      Therefore, all decisions will somehow rely on virtual functions or dynamic_cast , which is also essentially a virtual function.

      • Here is the very essence of the context that you cut out and put in place of the three points. The whole interest is that the name of a member of the base class is overlapped by the same name in a derivative. For functions, this works because they can be virtual, but not for data members. Although it would be interesting to have virtual data to access them directly using dynamic polymorphism - Dmitry
      • @ Dmitry How to put it ... Paraphrasing - "when I see dynamic_cast , I grab the keyboard." This is a rope, which, as many hope, you can attach different pieces of iron to a bike in order to get a beautiful Harley ... For me, it speaks of an ill-conceived design, and you need to change it, because sooner or later it will come to this anyway - if this is something serious. - Harry

      Because the ultimate goal is not specified, we will solve a specific task. To do this, we use CRTP :

       template<typename Derived> class Base { public: char val = 'a'; char GetVal() { return val; } auto GetDerivedVal() { return static_cast<Derived*>(this)->val; } virtual ~Base(){} }; class Derived: public Base<Derived> { public: char val = 'A'; virtual char GetVal() { return val; } }; int main() { Base<Derived> *pb = new Derived; std::cout << pb->GetVal() << std::endl; //Выведет: a std::cout << pb->GetDerivedVal() << std::endl; //Выведет: A delete pb; return 0; } 

      I do not know if this will suit you for real use, but this solves the problem from the question.


      If dynamism is necessary, then with some conditions (we know in advance all the types that we need) and using boost::variant , we can do the following:

       #include <boost/variant.hpp> using Variant = boost::variant<char, int>; class Base { public: char val = 'a'; virtual Variant GetVal() { return val; } virtual ~Base() {} }; class Derived: public Base { public: int val = 'A'; Variant GetVal() override { return val; } }; int main() { Base *pa = new Base; Base *pb = new Derived; std::cout << pa->GetVal() << std::endl; //Выведет: a std::cout << pb->GetVal() << std::endl; //Выведет: 65 delete pb; delete pa; return 0; } 
      • It seems to me that in this code there is no polymorphic behavior, since The pb pointer already has a specific type Base <Derived> at compile time, i.e. such a pointer can work only with objects of type Derived . The point of all this, if you can explicitly create a pointer like Derived * ? - Dmitriy
      • @ Dmitry, your question is clearly written: without resorting to virtual replacement get-functions? . Then what kind of polymorphic behavior can we talk about if you explicitly ask not to use virtual functions, which are the only way to implement polymorphism in C ++? - ixSci
      • But what if the type of the object is not known at the compilation stage, such as, for example, in the collection of objects that can be Base and Derived types, and which are handled through basic type pointers? - Dmitriy
      • @ Dmitry, no way. Unless you create a virtual function that will return something like boost::any , and then pull out the value from there. But for this you will need to know what is in any , and this is no longer suitable - dynamism is needed. You can of course limit the set of possible types and use the boost::variant , but it’s not clear what the task really is for you, so I can’t say if the solution is right. - ixSci
      • Thank. You gave a link to an article in which it makes sense only if such objects are passed to a function that is template : template <typename Impl> void executeCrtp (CrtpBase <Impl> & crtp, const std :: vector <unsigned> & indicies). Here you can just talk about static polymorphism - Dmitriy
      1. dynamic_cast . But this already leads to doubts about the design.

      2. Virtual substitution will only be for the matching method signature. Otherwise - overlap. Get only the same cast.

      • Does the return value refer to the method signature ? - Dmitriy
      • @ Dmitry, you are right, in general, the signature does not apply, but decides when override. : "It’s a function of the overridden function” - free_ze

      Functions can not differ only in the returned parameter, as an alternative, convert a little virtual method

       class Base { public: char val = 'a'; virtual void GetVal(char &_char) { _char = val; } virtual void GetVal(int &_int) = 0; }; class Derived : public Base { public: int val = 65; // был тип char - стал int virtual void GetVal(int &_int) { // теперь возвращаем объект типа int _int = val; } }; int main() { Base *pb = new Derived; char myChar; int myInt; pb->GetVal(myChar); pb->GetVal(myInt); std::cout << myChar << std::endl; //Выведет: a std::cout << myInt << std::endl; //Выведет: A delete pb; return 0; } 

      But it would be better to figure out what it is for. I think you can find a different approach.