访问现有基对象的受保护成员

Access protected members of an existing base object

本文关键字:受保护 成员 对象 访问      更新时间:2023-10-16

假设我有一个带有protected成员的基类:

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

和基类的派生类:

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

首先:我可以做这个,对吗?这完全合法吗?

如果是,那么问题是:

  • 我不能改变基类中的任何东西;
  • 我有一个基类对象,我需要访问它的m_attribute成员;

我应该先从这个基类对象向下转换到派生类对象,然后调用get_attribute()函数吗?像这样:

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

或者访问受保护成员的其他方法是什么?我知道好友函数是一个选项,但是我不能改变基类

中的任何东西。

我应该先从这个基类对象向下转换到派生类对象,然后调用get_attribute()函数吗?

绝对不是。基类的实例不是派生类的实例。您的转换格式错误。

这是一个有效的方法:

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

用法:

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

该组合通过复制构造派生类型的基子对象来工作。这当然取决于碱基是可复制的——你的Base是。这很容易调整工作与移动。

作为语法糖,可隐式转换为成员的类型。如果你愿意,你可以使用getter

如果基类重载后没有默认构造函数,并且没有默认构造函数,则派生类必须使用成员初始化列表初始化基类部分,否则无法实例化派生类,编译器会抱怨基类中缺少默认构造函数:

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;
}
  • 也不能将基类的地址强制转换为派生对象,但可以将基类的对象强制转换为派生对象。

所以在你的例子中写在main:

Derived* derived = static_cast < Derived*>(&baseObj); // is like writing:
char* cp = static_cast < char*>(&int); // you must convert a variable not a type
  • 为什么要从外部访问受保护的成员??请记住,公共继承将把基类的所有成员复制到派生类中,但不是私有的。

  • 使用友好型或者将成员数据设为公共可以从外部访问它但是它破坏了数据隐藏和封装的原则然而友好型在某些情况下是必须的并且没有其他选择那么小心使用但是将数据设为公共最好还是回到结构体

派生类可以访问和修改publicprotected基类的属性和方法。

那么,你不能将Base分为Derived。Derived继承自Base,所以Derived是一个Base。但是基类不是派生类(Car是Vehicle, Vehicle不是Car)。

所以如果你需要一个getter,直接放到Base中,或者实例化一个Derived而不是Base。

first:

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

这是无效且非法的。不会编译。你不能将Base静态转换为Base*

回答你的问题:

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

或者如果你想使用指针,因为你觉得你更酷:

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

EDIT: static_cast在运行时没有任何开销。它是静态的,因此它是编译时的东西。这两种方法将产生相同的结果。