简体   繁体   中英

C++ access member of templated derived class without typecast

Is it possible to acces a member of a derived class using a pointer to the base class?

// Example program
#include <iostream>
#include <vector>
#include <memory>
#include <string>

class A {
    public:
    std::string x = "this is the wrong x\n";
    };

template <class T>
class B : public A {
    public:
    T x;
    };

int main()
{
    std::vector<std::unique_ptr<A>> vector;
    auto i = std::make_unique<B<int>>();
    i->x = 6;
    vector.push_back(std::move(i));
    for(auto &element : vector){
        std::cout << element->x;
    }
}

Here I'm always getting the output from class A. I cannot typecast it because I don't know whether the element is of type A or type B in advance. Is there a proper way to do this?

The proper way would be to make a virtual function to perform the task like printing.

class A {
public:
    std::string x = "this is the wrong x\n";
    virtual ~A() = default;
    virtual void print() const { std::cout << x; }
};

template <class T>
class B : public A {
public:
    T x;
    virtual void print() const override { std::cout << x; }
};

int main()
{
    std::vector<std::unique_ptr<A>> vector;
    auto i = std::make_unique<B<int>>();
    i->x = 6;
    vector.push_back(std::move(i));
    for(auto &element : vector){
        element->print();
    }
}

If you have a pointer to a base class, you can only access things defined on that base class (without typecasting). For all the compiler knows, it is an instance of the base class and has nothing else.

Polymorphic behavior involves using virtual functions - derived classes can change which function is called when invoking a virtual function of the base class. Note that this mechanism does not exist for members (what would you change about a member? There's only the type, and changing that in a derived class makes no sense). So the only meaningful thing you can do with pointers to base classes that should have customized behavior is to call their virtual functions.

Now, you could think "ok, I'll just make access to x go through a virtual function", but the problem here is that you must specify the involved types when you declare the virtual function in the base class already. That makes sense: The compiler needs to know which types a function involves, even a virtual one. You may only pass and return different types in the overriding functions if they are "compatible" - see covariance and contravariance for more information.

So unless all your T are covariant, virtual functions cannot help you either.

The core flaw with your concept is that you want to have some type (ie element->x ) in a non-templated function depend on the dynamic type of some object (ie element ). That is impossible because the compiler must know the type of each expression at compile-time. So you must approach your problem differently.

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