链接时突然无法访问私有方法

Private methods suddenly inaccessible when chaining

本文关键字:访问 有方法 突然 链接      更新时间:2023-10-16

我有一个简单的类层次结构,其中包含一个基类和一个派生类。基具有派生类调用的两个受保护成员。从最近的一些 C# 经验来看,我认为最好使接口更流畅一点并允许方法调用的链接,因此与其调用this->A(),不如this->B()您可以调用this->A()->B()。但是,以下代码将无法编译:

#include <iostream>
class Base
{
protected:
Base* A()
{
std::cout << "A called." << std::endl;    
return this;
}
Base* B()
{
std::cout << "B called." << std::endl;    
return this;
}
};
class Derived : public Base
{
public:
void Test()
{
// Base::A and Base::B are private here.
this->A()   // This works fine
->B();  // Suddenly I cannot access my own private method?
}
};
int main()
{
Derived d;
d.Test();
return 0;
}

这将产生以下编译器错误:

main.cpp: In member function 'void Derived::Test()':
main.cpp:12:15: error: 'Base* Base::B()' is protected
Base* B()
^
main.cpp:26:21: error: within this context
->B();  // Suddenly I cannot access my own private method?
^

我还尝试使基类方法虚拟化,但这没有帮助。

我的C++生锈了,我似乎无法弄清楚这里发生了什么,所以帮助将不胜感激。我也想知道这是否是一个坏主意,因为C++ != C#和C++人不习惯如此流畅的界面。

类中的受保护成员只能通过派生类(即通过派生类的对象、引用或指向该派生类的指针)从派生类访问。

A()的返回类型是Base*,它不是派生类,这就是无法访问其受保护成员的原因。编译器不会跟踪它是否确实引用了同一个对象。

是的,您不能从Base *调用Base类的受保护方法。您可以认为受保护的方法是私有的,但不同的是它们也成为派生类的私有方法。

为了补充塞巴斯蒂安,这可以通过以下方式解决,但不是很好:

static_cast<Derived*>(this->A())->B();

您可以参考标准以获得问题的答案

11.2 基类和基类成员的可访问性 [class.access.base]

N 的基类 B 可在 R 处访问,如果

— an invented public member of B would be a public member of N, or
— R occurs in a member or friend of class N, and an invented public member of B would be     
a private or
protected member of N, or
— R occurs in a member or friend of a class P derived from N, and an invented public member of B would be a private or protected member of P, or
— there exists a class S such that B is a base class of S accessible at R and S is a base class of N accessible at R

如果通过 Base 指针引用成员,则上述子句均不声明。

这是正确的行为,您不能为只能通过派生类执行的不同类调用受保护的函数,因为当您调用this->A()时,它会返回一个 Base*,这是一个不同的类。原因是,如果你做了这样的事情,

class Derived : public Base
{
public:
void Test()
{
baseInstance->B(); // this shouldn't be possible. If the case was you can call it through a pointer or an object this would be possible.
}
Base* baseInstance; 
};

另外,最好指出派生和基this可能没有相同的地址,它可能具有不同的地址。当您实际将Base*转换为Derived*时,编译器将处理地址的差异,这使得如果像这样完成它就可以工作的原因static_cast<Derived*>(this->A())->B();