C++是否可以从同级第二个派生对象访问第一个派生对象的受保护基础数据成员?

In C++ is it possible to access a 1st derived object's protected base data member from a sibling 2nd derived object?

本文关键字:对象 派生 受保护 第一个 数据成员 访问 是否 C++ 第二个      更新时间:2023-10-16

我正在编写一个C++程序,其中有两个来自基类的派生对象,例如Derived_1和Derived_2。

在处理过程中,第一个对象调整基本数据成员(只是使用此处Derived_1的默认构造函数进行模拟)。然后,我想做的是从Derived_1对象中读取该数据,并在Derived_2的构造函数期间使用它来初始化Derived_2中的同一成员。

// -std=c++14
#include <iostream>
class Base {
public:
int data(void) { return data_; }
protected:
int data_{0};
};
class Derived_1 : public Base {
public:
Derived_1(void) { this->data_ = 42; }
};
class Derived_2 : public Base {
public:
// Derived_2(const Derived_1& a1) { this->data_ = a1.data_; }
};
int main() {
Derived_1 a1;
std::cout << "Derived_1 data: " << a1.data() << 'n';
// Derived_2 a2 = a1;
// std::cout << "Derived_2 data: " << a2.data() << 'n';
}

如果 Derived_2 中的构造函数未注释,则会发生此错误:

In constructor ‘Derived_2::Derived_2(const Derived_1&)’:
error: ‘int Base::data_’ is protected within this context
Derived_2(const Derived_1& a1) { this->data_ = a1.data_; }
^~~~~

我已经浏览了许多关于SO的相关问题,试图找到解决方案,(例如) 从基类指针访问派生私有成员函数 指向派生对象 和 为什么可以通过指向派生对象的基类指针访问派生私有成员函数? 但是如果我看到它,我目前很难找到答案。可能只是我缺乏经验。

感谢您帮助我解决这个问题。

是的,通过使Derived_2成为Derived_1friend是可能的:

class Derived_1 : public Base {
//This says that Derived_2 is a friend, which means that Derived_2
//can access every member in Derived_1
friend class Derived_2;
public:
Derived_1(void) { this->data_ = 42; }
};

所以现在你可以这样做:

class Derived_2 : public Base {
public:
Derived_2(const Derived_1& a1)
{ 
//Legal, Derived_2 is a friend of Derived_1, so it can access the
//protected member 'data_'
this->data_ = a1.data_; 
}
};

请注意,现在,Derived_2可以修改Derived_1的每个数据成员,而不仅仅是data_

第一个错误是派生类无法访问在基类中声明的data_以供使用。若要解决此问题,需要包含以下派生类:

using Base::data_;

现在,OOP 建议的是每个对象都有与之关联的明确定义的方法,并且没有变量可以直接访问。您可以执行以下操作之一:

class Derived_2 : public Base {
public:
Derived_2(const int& a1) { this->data_ = a1; }
};

并像这样使用它:

Derived_2 a2(a1.data());

或者你可以宣布Derived_2Derived_1的朋友,正如@Rakete1111在他的回答中提到的:

class Derived_1 : public Base {
//This says that Derived_2 is a friend, which means that Derived_2
//can access every member in Derived_1
friend class Derived_2;
public:
Derived_1(void) { this->data_ = 42; }
};

但是,如果这样做,Derived_1中的所有变量都可以直接访问Derived_2

编辑 1(根据要求):类的用法:

版本1:

class Derived_1 : public Base {
using Base::data_;
public:
Derived_1(void) { this->data_ = 42; }
};
class Derived_2 : public Base {
using Base::data_; 
public:
Derived_2(const Derived_1& a1) { this->data_ = a1.data(); }
};

版本2:

//Declaration of Derived_2 here for Derived_1 
//to know that a class with such a name exists
class Derived_2 : public Base;
class Derived_1 : public Base {
using Base::data_;
friend class Derived_2;
public:
Derived_1(void) { this->data_ = 42; }
};
class Derived_2 : public Base {
using Base::data_; 
public:
Derived_2(const Derived_1& a1) { this->data_ = a1.data_; }
};

派生类只能访问其自己的基类子对象的受保护成员。他们无权访问其他类的基受保护成员,即使该基与其自己的基是同一类型。

可能的解决方案:

  • 公开声明Base::data_
  • 或者宣布Derived_2Derived_1的朋友.