简体   繁体   中英

c++ inheritance abstract function?

I have a somewhat basic question on inheritance that i can seem to figure out, I've done a search and not found what I was looking for so I thought I'd ask here (not sure if title of what I'm looking for is correct).

To keep things simple I've made a bit of example code to illustrate what I'm not getting.

Basically if I have a parent class A and two child classes B & C , where A contains common stuff (say an id with get/set), while B & C have functions that are class specific. If you declare a class B like: A *bObject = new B(); how do you then access the class specific function A *bObject = new B(); how do you then access the class specific function bObj->specific()`?

I've tried virtual but that requires both B & C to have the same function name / prototype declared. I've also tried declaring the abstract in A , but that requires it to be prototype to be in A .

Where am i going wrong here? any help on this, probably basic issue would be helpful.

#include <iostream>
using namespace std;
// A class dec
class A
{
public:
    A(void);
    ~A(void);
    char id;
    void setId(char id);
    char getId();
};

// B class dec - child of A
class B :
    public A
{
public:
    B(void);
    ~B(void);
    void sayHello();
};

//C class dec - child of A
class C :
    public A
{
public:
    C(void);
    ~C(void);
    void sayGoodby();
};

//a stuff
A::A(void)
{
}
A::~A(void)
{
}
void A::setId(char id)
{
    this->id = id;
}
char A::getId()
{
    return this->id;
}

//b stuff
B::B(void)
{
    this->setId('b');
}
B::~B(void)
{
}

// c stuff
C::C(void)
{
    this->setId('c');
}
C::~C(void)
{
}
void C::sayGoodby()
{
    std::cout << "Im Only In C" << std::endl;
}
// main
void main ()
{
    A *bobj = new B();
    A* cobj = new C();

    std::cout << "im class: " << bobj->getId() << endl;
    bobj->sayHello(); // A has no member sayHello
    std::cout << "im class: " << cobj->getId() << endl;
    cobj->sayGoodby(); // A has no member sayGoodby
    system("PAUSE");
}

Thank you for your time!

A *bobj = new B();
A* cobj = new C();

Here instance of B and C is pointed by pointer of A. Since A have no virtual function for B and C's member function sayHello() and sayGoodbye(), they could not called by bobj->sayHello() and cobj->sayGoodbye() . It is not what polymorphism should be do.

Class A should be:

class A
{
public:
    A(void);
    ~A(void);
    char id;
    void setId(char id);
    char getId();

    virtual void sayHello(){/* to do */ };
    virtual void sayGoodbye(){ /* to do */ };
};

Then the bobj->sayHello(); and cobj->sayGoodbye(); could be called without complaning.

A *bobj = new B();

The static type of bobj is A * . So, at compile time, the compiler looks for the member functions in the class A definition, what ever you tried to access through bobj . Now,

bobj->sayHello();

the compiler will look for the sayHello in class A since the type of bobj is A * . Compiler doesn't care to look into the class B definition to resolve the call. Since the compiler didn't find it sayHello member in A , it is complaining.

However, the dynamic type of bobj is B * and that is a where call is dispatched depending on the dynamic type.

To resolve the issue, you need to virtual functions of the same in class A .

To access methods unique to a derived class, you need to cast the base class pointer to the correct derived class type first (a downcast):

A *bobj = new B();
bobj->sayHello(); // compile error
dynamic_cast<B*>(bobj)->sayHello(); // works
dynamic_cast<C*>(bobj)->sayGoodbye(); // run-time error - probably crashes with a segfault/access violation.

dynamic_cast ensures run-time type safety but adds a small overhead to the cast; for pointer casts, it returns a null pointer if the pointed-to object is not actually a B, and you should check the return value before using it. Alternatively, if you are really sure that the pointer you are casting is pointing to the correct object, you can use static_cast which saves you the cost of the run-time checking, but if the pointer is not pointing to the right object, you get undefined behavior.

You can use a down cast via dynamic_cast<> . You can implement a template method in your base class A to facilitate the down cast:

class A
{
public:
    A(void);
    virtual ~A(void);
    char id;
    void setId(char id);
    char getId();

    template <typename CHILD, typename R, typename... ARGS>
    R invoke (R (CHILD::*m)(ARGS...), ARGS... args) {
        CHILD *child = dynamic_cast<CHILD *>(this);
        if (child) return (child->*m)(args...);
        std::cout << "down cast error: " << typeid(CHILD).name() << std::endl;
    }
};

If that particular instance of A was not the base of CHILD , then dynamic_cast<CHILD *>(this) result in NULL . Note that the virtual destructor in A is required for the dynamic_cast<> to work.

So, you can use it like this:

std::unique_ptr<A> bobj(new B());
std::unique_ptr<A> cobj(new C());

bobj->invoke(&B::sayHello);
bobj->invoke(&C::sayGoodbye);
cobj->invoke(&B::sayHello);
cobj->invoke(&C::sayGoodbye);

Only the first and last invocations are valid. The middle two will cause the "down cast error" message to be printed.

if you really want to call a function like this, you can do like this:

A* bobj = new B();
((B*)bobj)->sayHello();//this can be dangerous if bobj is not an instance of class B

however, the problem here is you do the design wrongly. basically, if you create an class A, and subclass it to B and C. And then assign A* bobj = new B(); you are splitting the interfaces and implementations. That means you will use bobj as if it is an instance of class A. and you will not call the functions in B or C. B & C are implementations of interface class A.

it's just like you hire someone to build your house. You give them your blueprint(interfaces) and hire them to build. you can alter the blueprint as you like, they will do whatever in blueprint. but you can't order them directly(just like you can't call the sayHello() directly from bobj).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM