1

Lets say I have a base class with protected member:

class Base  
{
public:
    Base(int data)
    : m_attribute(data) {}

protected:
    int m_attribute;
};

and derived class from base:

class Derived : public Base 
{
 public:
    int get_attribute()
    {
        return m_attribute;
    }   
};

First of all: I can do this, right? Is this totally legal?

If yes, then here is the question:

  • I can't change anything in a Base class;
  • I have a Base class object, and I need to access its m_attribute member;

Should I do downcasting from this base class object to derived class object first, and then call get_attribute() function? Something like this:

Base base(5);
Derived* derived = static_cast < Derived*>(&base);
int base_attribute = derived->get_attribute();

Or what are other ways to access protected member? I know that friend function is an option, but I can't change anything in the base class

  • First question : Yes, you can, make your dreams come true – Treycos Oct 30 '16 at 22:41
  • Your static cast isn't doing anything – Treycos Oct 30 '16 at 22:43
  • 1
    Possible duplicate of [Why can't I access a protected member from an instance of a derived class?](http://stackoverflow.com/questions/967352/why-cant-i-access-a-protected-member-from-an-instance-of-a-derived-class) – Nick Pavini Oct 30 '16 at 23:22
  • Nope, that post doesn't explain how to access protected members of already existing object – Alex Shirokov Oct 30 '16 at 23:28
  • 2
    See [this](http://stackoverflow.com/questions/424104/can-i-access-private-members-from-outside-the-class-without-using-friends) for some super clever solutions... Especially [this answer](http://stackoverflow.com/a/3173080/3093378). – vsoftco Oct 30 '16 at 23:37
  • And a full explanation [here](http://cpp.kjx.cz/private_backdoor.html). Basically the access rules are not enforced in template instantiations, which makes this whole magic possible. – vsoftco Oct 30 '16 at 23:47
  • It is weirdly interesting solution :) – Alex Shirokov Oct 30 '16 at 23:51

4 Answers4

4

Should I do downcasting from this base class object to derived class object first, and then call get_attribute() function?

Most definitely not. An instance of a base class is not an instance of a derived class. Your conversion is ill-formed.

Here is a valid way:

struct kludge : Base {
    kludge(const Base& b): Base(b) {}
    operator int() {
        return m_attribute;
    }
};

usage:

Base base(5);
int foo = kludge(base);

This kludge works by copy constructing the base sub object of the derived type. This of course depends on the base being copyable - which your Base is. It's easy to tweak to work with movable as well.

As a syntactic sugar, the kludge is implicitly convertible to the type of the member. If you prefer, you could use a getter.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Its highly specific usage example. What if my base class is very complicated, which has lots of parameters, and no so easily constructed? – Alex Shirokov Oct 30 '16 at 23:25
  • @AlexShirokov as long as the base is copyable (or movable with small change to the kludge) the complexity of construction of base othwewise has no effect. – eerorika Oct 30 '16 at 23:26
  • All right, and how about operator in() ? Will m_attribute be access in a regular member function? – Alex Shirokov Oct 30 '16 at 23:30
  • @AlexShirokov sure, as I said in the answer: *If you prefer, you could use a getter.* There is nothing special about the conversion operator. – eerorika Oct 30 '16 at 23:31
  • This is what I was looking for :) [link](http://coliru.stacked-crooked.com/a/66bada198893a1c8) – Alex Shirokov Oct 30 '16 at 23:37
  • @AlexShirokov you're free to do it that way. I prefer the shorter syntax of my way :) – eerorika Oct 30 '16 at 23:40
  • Thanks @user2079303 ! I feel like I actually learned something today :) – Alex Shirokov Oct 30 '16 at 23:44
  • 1
    @AlexShirokov If this helped you should consider accepting an answer by clicking on the check mark. –  Oct 31 '16 at 01:08
0

if base class doesn't have a default constructor after overloading it to take some arguments and no default one is there then the derived classes must use member-initializer list to initialize the base part otherwise you cannot instantiate the derived class getting the compiler complaining about missing default constructor in base class:

class Base  
{
    public:
    //  Base(){} default constructor by default the compiler creates one for you unless you overload it so the next one taking one parameter will hide this one
        Base(int data) // hides the default ctor so derived classes must use member-initializer list
        : m_attribute(data) {}

    protected:
        int m_attribute;
};


class Derived : public Base 
{
    public:
        Derived() : Base(0){} // you must use member intializer list to initialize the part Base
        //Derived(int x) : Base(x){} // also ok
        int get_attribute(){ return m_attribute; }   
};

int main()
{
    Derived dervObj;

    Derived* derived = static_cast < Derived*>(&baseObj);
    int base_attribute = derived->get_attribute();
    cout << base_attribute << endl;

}
  • also you cannot cast the address of class base to derived object but cast an object of base class to derived one.

so in your example writing in main:

Derived* derived = static_cast < Derived*>(&baseObj); // is like writing:
char* cp = static_cast < char*>(&int); // you must convert a variable not a type
  • why you want to access protected members from outside??? keep in mind that public inheritance will copy all the members of base to derived class but private.

  • using friendship or making member data public will make it possible to access it from outside but it undermines the principles of data-hiding and encapsulation however friendship in some cases it's a must and there's no other alternative then use it carefully but making data public it's better to get back to structs

Raindrop7
  • 3,889
  • 3
  • 16
  • 27
-1

The Derived class can access and modify the public and protected Base class properties and methods.

Then, you can't case Base into Derived. Derived inherit from Base, so Derived is a Base. But a Base is not a Derived (a Car is a Vehicle, a Vehicle is not a Car).

So if you need a getter, put it directly into Base, or instanciate a Derived instead of a Base.

Ludonope
  • 963
  • 9
  • 14
-1

Firstly:

Derived* derived = static_cast < Base*>(base);

This is not valid and illegal. Won't compile. You can't static cast Base to Base*.

And to answer your question:

Base base(5);
Derived& derived = static_cast<Derived&>(base);
std::cout << derived.get_attribute();

Or if you want to use a pointer because you think you're cooler:

Base base(5);
Derived* derived = static_cast<Derived*>(&base);
std::cout << derived->get_attribute();

EDIT: static_cast doesn't have any overhead on runtime. It is static, hence it's a compile-time thing. Both methods will yield the same result.

DeiDei
  • 10,205
  • 6
  • 55
  • 80
  • What operation is going to be faster? Casting to a reference or to a pointer? – Alex Shirokov Oct 30 '16 at 22:47
  • Thanks @DeiDei ! Just a quick follow up question: Are there other ways to access protected members, that I am not aware of. Sort of like "best practices". What are the options here? – Alex Shirokov Oct 30 '16 at 22:52
  • @AlexShirokov The best practice is to *not* access members if the declarer chose to declare them non-public, – Adrian Colomitchi Oct 30 '16 at 22:55
  • @Adrian Colomitchi What if the declarer created a class Animal long ago. He made the attributes non-public, and there are no getter functions. NOW, we decided to add serialization functionality to this class. But we can't change anything inside the class. In order to serialize the class, we need a way to access its members. What are the options here? How would you recommend to add this functionality? – Alex Shirokov Oct 30 '16 at 23:00