简体   繁体   中英

C++ How to call a derived base class function from main

I have three classes that each inherit from the other: A is inherited by B is inherited by C. I also have one virtual function in each of these classes. I want to create an A-class pointer holding a C-class object and call the B-class function like so:

class A
{
public:
    virtual void doStuff() = 0;
};

class B : public A
{
public:
    virtual void doStuff() override;
};

class C : public B
{
public:
    void doStuff() override;
};

void B::doStuff()
{
    std::cout << "Starting doStuff in B\n";
    doStuff();
    std::cout << "Ending doStuff in B\n";
}

void C::doStuff()
{
    std::cout << "doStuff in C\n";
}

int main()
{
    A *pointer = new C();
    pointer->B::doStuff(); // This doesn't work
}

If I change my main slightly, I get the correct output:

int main()
{
    B *pointer = new C(); // Changed A to B
    pointer->B::doStuff();
}

Output

Starting doStuff in B
doStuff in C
Ending doStuff in B

How can I change my original code to use an A-class pointer and preferably only one function name?

The issue is that B::doStuff , which refers to the implementation of doStuff at class B , is not a member of A . If you are sure that the pointer is actually pointing to an instance of B or something derived from B , then you could write the following:

int main()
{
    A *pointer = new C();
    reinterpret_cast<B*>(pointer)->B::doStuff(); // This should work
}

If you cannot be sure about the instance type, use a dynamic_cast .

A pointer of type A can't know for certain that the B version of doStuff is accessible by default; you need to cast the pointer first.

int main()
{
    A *pointer = new C();
    if(B *b_ptr = dynamic_cast<B*>(pointer)) 
        b_ptr->B::doStuff(); //Will only be executed if dynamic_cast was successful
}

Also, if you're going to use polymorphism like this, make sure you make A's destructor virtual as well, or cleanup won't behave.

class A
{
public:
    virtual void doStuff() = 0;
    virtual ~A() noexcept = default;
};

Here is some sample code to show why I want to do this. This code will output syntax similar to XML. Calling the "middle" class's function allows me to surround any derived class with the correct "IdentifiedRegion" tags.

#include <iostream>
#include <string>
#include <vector>

class Region
{
public:
    virtual void doStuff(std::string tabs) = 0;
};

class IdentifiedRegion : public Region
{
public:
    virtual void doStuff(std::string tabs) override;
};

class CircularRegion : public Region
{
public:
    CircularRegion(int latitudeIn, int longitudeIn, int radiusIn) : latitude(latitudeIn), longitude(longitudeIn), radius(radiusIn) {}
    void doStuff(std::string tabs) override;
private:
    int latitude;
    int longitude;
    int radius;
};

class CountryRegion : public IdentifiedRegion
{
public:
    CountryRegion(int countryCodeIn) : countryCode(countryCodeIn) {}
    void doStuff(std::string tabs) override;
private:
    int countryCode;
};

class StateRegion : public IdentifiedRegion
{
public:
    void doStuff(std::string tabs) override;
    StateRegion(std::string abbreviationIn) : abbreviation(abbreviationIn) {}
private:
    std::string abbreviation;
};

void IdentifiedRegion::doStuff(std::string tabs)
{
    std::cout << tabs << "<IdentifiedRegion>\n";
    doStuff(tabs + "\t");
    std::cout << tabs << "</IndentifiedRegion>\n";
}

void CircularRegion::doStuff(std::string tabs)
{
    std::cout << tabs << "<CircularRegion>\n";
    std::cout << tabs << "\t" << "<latitude>" << latitude << "</latitude>\n";
    std::cout << tabs << "\t" << "<longitude>" << longitude << "</longitude>\n";
    std::cout << tabs << "\t" << "<radius>" << radius << "</radius>\n";
    std::cout << tabs << "</CircularRegion>\n";
}

void CountryRegion::doStuff(std::string tabs)
{
    std::cout << tabs << "<CountryRegion>\n";
    std::cout << tabs << "\t" << "CountryCode>" << std::to_string(countryCode) << "</CountryCode>\n";
    std::cout << tabs << "</CountryRegion>\n";
}

void StateRegion::doStuff(std::string tabs)
{
    std::cout << tabs << "<StateRegion>\n";
    std::cout << tabs << "\t" << "<Abbreviation>" << abbreviation << "</Abbreviation>\n";
    std::cout << tabs << "</StateRegion>\n";
}

int main()
{
    Region *country = new CountryRegion(12);
    Region *state = new StateRegion("WA");
    Region *radius = new CircularRegion(10, 20, 30);

    reinterpret_cast<IdentifiedRegion*>(country)->IdentifiedRegion::doStuff("");
    reinterpret_cast<IdentifiedRegion*>(state)->IdentifiedRegion::doStuff("");
    radius->doStuff("");
}

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