Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 关于受保护成员函数和派生类访问的混淆_C++_Visual Studio_Inheritance - Fatal编程技术网

C++ 关于受保护成员函数和派生类访问的混淆

C++ 关于受保护成员函数和派生类访问的混淆,c++,visual-studio,inheritance,C++,Visual Studio,Inheritance,我与一位同事讨论了为什么以下内容不能在Visual Studio 2008中编译: class base { protected: virtual void f(){} }; class a : public base { public: void fa(base* pb) { pb->f(); // error C2248: 'base::f' : cannot access protected member declared in class

我与一位同事讨论了为什么以下内容不能在Visual Studio 2008中编译:

class base
{
protected:
    virtual void f(){}
};

class a : public base
{
public:
    void fa(base* pb)
    {
        pb->f(); // error C2248: 'base::f' : cannot access protected member declared in class 'base'
    }
};
他认为这是完全合理的,但我认为这是一个奇怪的限制,如果我想要
base
及其所有派生类成为一个封闭系统,我仍然需要将
base
的一些成员公开,以便他们都可以通过公开派生的共享接口相互交谈


是否有一些我没有想到的用例,允许访问这些受保护的成员可能会破坏受保护成员的性质?

如果编译器允许这样的事情,那么您可以很容易地破坏封装。想想这个:

base b;
a foo;
foo.fa(b); // we can now easily access/modify protected elements of `b`
在这种情况下,派生对象
foo
和基
b
之间没有关系,但是您可以使用派生对象访问其“内脏”。这应该是不可能的(至少是imho)

只需在
a.fa()
内部执行
f()
就可以了,因为您只需修改
a
的基本部分,而不是一些不相关的对象

更具体地说,您可以编写一个“包装器”,它将对任何类禁用
protected

#include <iostream>

class Base
{
public: // protected in your case, public here so it compiles
    int x{42};
public:
    int getx() {return x;}
};

template<typename T> // wrapper
class DisableProtected: public T
{
public:
    void modify(Base* b)
    {
        b->x = 24;
    }
};

int main()
{
    Base base;
    std::cout << base.getx() << std::endl;
    DisableProtected<Base> foo; 

    foo.modify(&base); // can modify any Base
    std::cout << base.getx() << std::endl;
}
#包括
阶级基础
{
public://在您的情况下受保护,此处为public,因此它可以编译
int x{42};
公众:
int getx(){return x;}
};
模板//包装器
类DisableProtected:public T
{
公众:
无效修改(基本*b)
{
b->x=24;
}
};
int main()
{
基地;
std::cout接近重复项:

是否有一些我没有想到的用例,允许访问这些受保护的成员会破坏受保护成员的性质

我相信这是为了防止一个派生类与兄弟派生类的不变量相混淆

class A {
    protected: void foo();
};
class B : public A {
    // complicated code
};
class C : public A {
    void bar(B* b) {
        b->foo();
    }
};

这有效地允许
C
只修改
B
A
子对象,这可能会违反
B
对其
A
子对象施加的不变量,而
C
是不可能知道的。

有趣的故事。我刚刚从比亚恩那里得到了关于这个主题的回复。这是他的回复

考虑

class B : public base
{
public:
    // ...
};

A a;
B b;
a.f(&b); // a manipulated b's base
这导致了一些微妙的错误。这是有效的:

class A : public base
{
public:
    void fa(base* pb)
    {
        f();     // use your own base
    }
};

我不确定这是否是一件可怕的事情。在我看来,强迫我公开那些不应该公开的成员肯定没有那么邪恶。@cppgy我同意,但总体而言,通过我提到的方案,使用你的方案基本上使
受到保护
公开
相同。这可能是Stroustrup不允许的原因否则,任何人都可以使用指向
Base
的指针编写一个包装器,然后通过包装器访问任何
Base
对象的受保护成员。邪恶?不是真的,但是
protected
失去了它的意义。我不确定我是否相信这个参数。你不是自己在修改
b
的元素,你是在这样做g通过一种逻辑上应该能够修改这些元素的方法来访问它。与
private
的保护相比,您可以毫无问题地访问另一个对象的私有元素。@vsoftco这就是受保护和私有的区别。受保护是一种更允许的数据隐藏,允许一些访问在某些情况下。在我看来,如果你想阻止你所描述的问题,private就足够了。@不是你的示例,而是一个不涉及派生类的类似示例。类方法可以访问自己的私有成员,也可以访问该类的另一个对象的私有成员(通过指针或引用)例如,你应该让他在这里贴一个答案:))