0

Based on Is it possible to pass derived classes by reference to a function taking base class as a parameter, consider this example:

class base{};
class derived:public base{
public:
    int derived_member;
};
void func(base * bPtr){
    bPtr->derived_member;
}
int main(int)
{ 
    auto derivedPtr = new derived();
    func(derivedPtr);
    return 0;
} 

The above code gives error. Is there any way to pass a derived class into a function that receives a base class without declaring the members of the derived class in the base class?

JNo
  • 89
  • 12
  • 4
    Short answer is no. – R Sahu Jul 18 '19 at 16:36
  • 2
    this is indication that you did something wrong with abstractions. `base` doesn't cover functionality which you need or your inheritance design is wrong. There is a way to workaround this issue, see `static_cast` and `dynamic_cast` in your C++ book you are learning from, but like I wrote it is a workaround. – Marek R Jul 18 '19 at 16:36
  • 2
    Why can't you pass the derived class? What would your function do if it was passed a base class instead of a derived through a base pointer? – Artyer Jul 18 '19 at 16:36
  • 1
    You could make `virtual` functions to set/get the member variable. Then calling those functions via the base class pointer would invoke the derived class versions via dynamic dispatch and you could get the result you are after. – Jesper Juhl Jul 18 '19 at 16:44
  • When a program "gives error". It is useful to read the error message. – eerorika Jul 18 '19 at 17:07
  • X vs. Y maybe - what are you trying to do with this member access? We could better help with that beyond "this way you are trying to do it doesn't work" (which you already knew :-) ). – IdeaHat Jul 18 '19 at 17:09
  • Apart from reading the error, you would improve your question by actually quoting the error. Then, others could just do a search for the error message to get help. Of course, you did that already and didn't find anything. If you find irony in this comment, you can keep it. ;) – Ulrich Eckhardt Jul 18 '19 at 17:17
  • @UlrichEckhardt you are right. But I think the error is rather too obvious! Dont you think so? – JNo Jul 18 '19 at 17:20
  • 1
    @JalilNourisa Depends. You haven't told us what it is. – eerorika Jul 18 '19 at 17:20
  • Hi, the problem is that the class `base` does not have the `derived_member` property, so it is not possible use it. Declare `derived_member` in `base` class and remove from it from the `derived`class. – Jorge Omar Medra Jul 18 '19 at 18:54
  • @JorgeOmarMedra the whole point of the question based on the fact that the "derived_member" is defined in the derived class and not in the base class. Otherwise, it's straightforward. Thanks for your contribution though – JNo Jul 18 '19 at 21:26

3 Answers3

2

Jail.

You can do it using shared_ptr, dynamic_pointer_cast and static_cast, as i show you in the above code.

BTW, be careful with the design of your class because it could be affected at the time of derived it and casting, as you can see in the second case of the class DerivedB where the address of the variable derived_member is taken by the variable new_member.

#include<memory>
#include<iostream>

class Base {};

class DerivedA :public Base {


public:
    int derived_member;
};

class DerivedB :public Base {

public:
    int new_member;
    int derived_member;
};

void func(const std::shared_ptr<Base> &bp) {

    DerivedA* a = static_cast<DerivedA*>(bp.get()) ;
    std::cout << " VALUE MEMBER A: " << a->derived_member << std::endl;

}

int main(int)
{


    std::shared_ptr<DerivedA> bpA = std::make_shared<DerivedA>();
    std::shared_ptr<DerivedB> bpB = std::make_shared<DerivedB>();

    bpA->derived_member = 666;
    bpB->new_member = 0;
    bpB->derived_member = 667;

    std::shared_ptr<Base> pa = std::dynamic_pointer_cast<Base>(bpA);
    std::shared_ptr<Base> pb = std::dynamic_pointer_cast<Base>(bpB);

    func(pa);
    func(pb);

    return 0;
}

The output:

 VALUE MEMBER A: 666
 VALUE MEMBER A: 0

But, if you are looking for a solution which implies to call derived_member without doing the cast to a Derived class, it is not possible because the class Base does not have the variable derived_member in its definition.

Jorge Omar Medra
  • 978
  • 1
  • 9
  • 19
0

Is there any way to pass a derived class into a function that receives a base class

Yes, if you pass a pointer or a reference to the base.

how to pass a derived class as a function argument

For example:

void func(base* bPtr);
int main(int) { 
    derived d;
    func(&d);

without declaring the members of the derived class in the base class?

It is only possible to declare members of the base class in the definition of the base class. Direct members of the derived class can only be declared in the definition of the derived class, although the members of the base class object can are visible to the derived class as well.

Whatever members you declare in the base class has no effect on how derived classes can be passed to functions that take the base class as an argument.


what if the derived class members are not in the parent class

Then you cannot access those members through the pointer to base.

void func(base * bPtr){
    bPtr->derived_member;

Indeed, the above ill-formed, because base has no such member.

In order to access members of the derived class, you should pass a pointer (or reference, or possibly a copy) to the derived class:

void func(derived*);
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • since the first part of your answer is not related to my question and is already answered somewhere else, pls omit it so I can confirm your answer – JNo Jul 18 '19 at 17:22
  • @JalilNourisa The first part answer the question that you asked. I'll keep it for completeness. – eerorika Jul 18 '19 at 17:23
  • my question is clear, "Is there any way to pass a derived class into a function that receives a base class without declaring the members of the derived class in the base class?". In the first part, you are answering the question, "how to pass a derived class for a function that receives based class?", which is answered in the post that I cited in start of my question – JNo Jul 18 '19 at 17:48
  • @JalilNourisa No; It answers the whole question. Whether you declare members in a base class has no effect on the answer. I've now added clarification. – eerorika Jul 18 '19 at 17:48
0

I believe? this is most popular design error once people start learning OOP. Actual approach should be in quite opposite direction and formulated as "Liskov substitution principle" https://en.wikipedia.org/wiki/Liskov_substitution_principle

Back to our case: so, you want to access derived_member. Ask yourself: you need the member because of what? So, instead of directly manipulating the field, it's better to provide a method in the base class. Then, derived class can use that derived field and do the job you want. So, the issue you have is becuse you're trying to extract part of the derived class logic just out of it. Wrong!

Example: engines. Base class should have a method like startEngeine(). Car engine should then assign two things like this:

override startEngeine()
{
    isKeyInserted = true;
    turnKey();
}

More complex engines may require a lot of extra work (moreover, they can be keyless at all, like army vehicles)

override startEngeine()
{
    checkOilLevel(); // can throw if oil level is low
    while (oilPressure < 10)
    {
        activateOilPump();
    }
    activeCylindersCount = 4;
    isStarterActive = true;
    ... etc ...
}

So, in your case, you're trying to expose isKeyInserted and activeCylindersCount to outer world, and there is no reason for that. Let them be hidden inside, use your base class as a contract and derived classes as a way to implement that contract.

Yury Schkatula
  • 5,291
  • 2
  • 18
  • 42