C++保护访问

3

有没有办法在不继承的情况下访问类中的受保护变量。

class ClassA{
  protected:
    int varA; 
};

class ClassB{
  protected:
    ClassA objectA;

};


ClassB theMainObject;

我想通过theMainObject访问varA。
8个回答

5
您可以将classB设为classA的友元。
class ClassA{
  protected:
    int varA; 

  friend ClassB;
}

但是使用访问器可能更好,因为这样你就不会将类耦合在一起。

class ClassA{
  int getA() { return varA;}
  void setA(int a) { varA = a; }
  protected:
    int varA; 
}

3

拥有一个访问器函数是唯一的方法,即:

public:
   int getVarA(){return varA;}

你应该将其改为 int getCarA() const - Björn Pollex
你是对的 @Space_C0wb0y,我通常太懒了,不想标记const函数 :p - deek0146

2

添加标准的getter/setter函数:

int ClassA::GetVarA()  
{  
    return varA;
}  
BOOL ClassA::SetVarA(int nNewVar)  
{  
    // Perform verifications on nNewVar... Return FALSE if didn't go well.  

    // We're satisfied. Set varA to the new value.  
    varA = nNewVar;  

    return TRUE;
}

1

你不能直接从theMainObject访问varA,而且很可能不应该这样做。对于无关的类(例如你的两个示例类),protectedprivate相同,因此varA不可见。使用ClassA的常规API来操作其状态。

如果varAClassA结果状态的一部分,并且您只需要读取它,则应向该类添加公共访问器:

public:
   int getVarA() const
   {
       return varA;
   }

1
-1 是因为你不喜欢我的创意回答,或者认为作者不知道如何添加访问器!!! :) - Hovhannes Grigoryan
我同意。但是我不会给它负评,因为我很感激这个帮助。 - user346443

1

friend 是你的朋友。在想要访问的类中使用该关键字,作为你想要使用的类的友元!


1
除了将ClassB设为ClassA的友元之外,还有一些标准和非标准的方法可以访问ClassA的内部。您可以阅读Herb Sutter的文章来了解它们。

0

我假设修改ClassA的定义是被禁止的。

这里有一个棘手的方法,但我不鼓励你使用它 :)

class ClassA
{
protected:
   int varA; 
};

class ProtectedRemover // magic thing
{
public: // <- Note this! :)
   int varA;
};

class ClassB
{
protected:
   ClassA objectA;

public: // Just add two methods below

   int getProtectedVarA()
   {
      return reinterpret_cast<ProtectedRemover*>(&objectA)->varA;
   }

   void setProtectedVarA(int i)
   {
      reinterpret_cast<ProtectedRemover*>(&objectA)->varA = i;
   }
};

int main()
{
   ClassB theMainObject;

   // Set protected thing.
   theMainObject.setProtectedVarA(3); 

   // Get protected thing.
   std::cout << theMainObject.getProtectedVarA() << std::endl;
}

所以有一种方法可以访问和修改受保护/私有数据。
谁曾经认为这是不可能的,请点赞;)


2
-1 这是未定义的行为,因为就编译器所知,这些类型是不相关的,特别是如果 ClassA 有虚方法而 OP 没有展示给我们。 - Mark B
我的示例中没有任何未定义的行为! :) - Hovhannes Grigoryan
1
如果不是你毫无意义的恶意投票和评论 Mark-B 的回答,我肯定会为你有创意的回答点赞(而且确实不错)。太遗憾了朋友,这不是应对批评的方式。 - Assaf Levy
1
reinterpret_cast 的唯一允许操作是将其转换回原始类型。所有其他用途都会引发 UB(未定义行为)。无论如何,在许多编译器中可能会起作用。 - Tadeusz Kopec for Ukraine
2
@Hovhannes 这是未定义的行为。仅仅因为它偶然起作用并不意味着这是任何更少的真实,它可能无法在某些编译器上工作,甚至是同一编译器的未来版本。 - deek0146
显示剩余4条评论

0

正如Mark B所提到的,Hovhannes Grigoryan提出的解决方案并不安全,可能会因为ProtectedRemover和classA无关而产生意外行为...

我过去使用过这个方法,我认为它可能更安全:

class ClassA
{
protected:
   int varA; 
};

class ProtectedRemover : public ClassA // now, they are related!
{
public: // <- Note this! :)
   int getA() { return varA; }
   void setA( int a ) { varA = a; }
};

class ClassB
{
protected:
   ClassA objectA;

public: // Just add two methods below

   int getProtectedVarA()
   {
      return ((ProtectedRemover)*(&objectA))->getA();
   }

   void setProtectedVarA(int i)
   {
      ((ProtectedRemover)*(&objectA))->setA(i);
   }
};

请注意,这不会对获取未确定的行为造成任何风险......但可能比原始解决方案少一些,其中ProtectedRemover和classA无关....如果ClassA有大量属性,则更容易实现!

除非您真的没有其他选择(无法通过使您的类成为友元或添加settter/getter来修改classA),否则仍不建议使用!

没有什么是真正不可能的....


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接