在C++中继承私有成员

24

假设一个类有私有数据成员,但是setter和getter在公共作用域中。如果你从这个类继承,你仍然可以调用那些setter和getter - 从而访问在基类中的私有数据成员。既然派生类不能继承私有数据成员,那么这是如何可能的呢?


12
派生类确实会继承私有数据成员。 - Agnel Kurian
2
更加令人困惑的是,您可以覆盖基类的私有虚函数。 - Björn Pollex
1
@Space_C0wb0y:一点也不难懂。这被称为模板方法模式(可惜与C ++模板无关)。 - Billy ONeal
2
当你为属性添加getter和setter时,请三思而后行:有时它们完全没问题,但其他时候应该通过另一个更具描述性的接口完成工作。 - Mark B
7个回答

40

派生类不会继承私有数据成员的访问权限。尽管如此,它会继承完整的父级对象,其中包含该类声明的任何私有成员。


1
@user265260:可能吧,但为什么要这样做呢?这让我感到很担心。成员变量是私有的,这是有原因的,如果你可以随意更改它们的值,就会破坏对象的完整性。此外,如果布局发生了变化(在不同的编译之间可能会发生变化;一个具有size_t成员的对象在32位和64位编译中可能具有不同的布局),你就会覆盖完全不同的数据。 - David Thornley
5
或许在你所使用的平台上可以奏效,但这并非必需。永远都不是必须的。 - Billy ONeal
只是为了好奇,想要尝试一下瞎搞和黑客技巧,我在想这个是如何实现的。 - shreyasva
2
是的,你可以使用this并相应地进行偏移来以一种狡猾且不可移植的方式操作私有数据。 - Emile Cormier
1
@user265260:如果想了解程序“底层”发生了什么,最好的方法是启动调试器并查看对象及其数据成员的地址。您还可以打开调试器的“内存”视图,查看数据在内存中的位置。请记住,您将看到的行为是特定于平台/编译器的。 - Emile Cormier

11

这取决于继承类型。如果你私有继承,那么派生类就无法访问基类的私有成员。

Access                      public     protected    private
-----------------------------------------------------------
members of the same class      yes           yes        yes
members of derived classes     yes           yes         no
not members                    yes            no         no

3
我认为这个答案可能会误导或者至少不准确。@JRL请尽量让它更清晰明了。 - rineez
这并不回答所问的问题。 - Géry Ogam

4

因为getters和setters是公共的,它们可以被任何人调用,而不仅仅是派生类。


2
我的疑惑是,既然不能继承私有数据成员,那么你是如何操作它们的值的呢? - shreyasva
1
而那些getter和setter是基类的成员,因此它们可以访问私有数据。 - amertune
3
“clearly you cannot inherit them”这句话是错误的。您不能继承它们。 - John Dibling
5
Adam希望保持他的车钥匙私有,这样只有他可以使用。即使是他的孩子也没有权限。然而,如果他提供一个公共的获取方法来获取他的车钥匙,那么他就给了整个城镇许可,让他们来开他的车。当然,这也包括他的孩子。 - David
谢谢 @David,这正是我需要的东西来说服自己。 - Aayush Neupane

4
它们被包含在内,但不被继承。这意味着:
- 任何继承类型(`: public SomeClass`、 `: protected SomeClass` 或者等同于 `: private SomeClass` 的 `: SomeClass`)都无法从子类方法或外部(分别为 `this->a` 和 `someobject.a`)访问其内容; - 它们仍将存在 - 占用为子类实例分配的内存空间; - 继承的方法将能够访问该私有字段。
因此,基本上 `protected` 不可见外部,但可见内部和派生类(如果没有使用 `: private Parent`),而 `private` 对于派生类和父类之外均不可见;它仅对父类方法可见,即使它们已经被继承(但未被重载)。

2
你可以通过将setter和getter的访问权限设置为public来访问它们,然后像这样访问它们。
*.h


class Mamifere
{
private:
    int a;
public:
    Mamifere();
    virtual ~Mamifere();
    int getA();
    // ~Mamifere(); //le delete dans le exp02() affiche seulement mamifere mort :( destructeur de la class mere 
    void manger() ;
    virtual void avancer() const;
};


class Deufin:public Mamifere{
public:
    Deufin();
    void manger() const;
    void avancer() const;
    ~Deufin();
};




*.cpp

Mamifere::Mamifere(){
        printf("nouveau mamifere est nee\n");
        this->a=6;
    }

Mamifere::~Mamifere(){
        printf("mamifere Mort :(\n");
    }
void Mamifere::manger() {
    printf("hhhh   je mange maifere %d\n",Mamifere::getA());
    }
void Mamifere::avancer() const{
    printf("allez-y Mamifere\n");
}

Deufin::Deufin(){
    printf("nouveau Deufin  est nee\n");
}
int Mamifere::getA(){
    return this->a;
}
void Deufin::manger() const{
    printf("hhhh   je mange poisson\n");

}
void Deufin::avancer() const{

    printf("allez-y Deufin\n");
}

Deufin::~Deufin(){
    printf("Deufin Mort :(\n");
}



main.cpp





void exp031(){
    Mamifere f;//nouveau mamifere est nee   //   nouveau Deufin  est nee
    Deufin d;

    f.avancer();//allez-y Deufin (resolution dynamique des lien  la presence de mot cle virtual)
    f.manger();//hhhh   je mange maifere (resolution static des lien pas de mot cle virtual)
    printf("a=%d\n",d.getA());//Deufin Mort :(   mamifere Mort :( (resolution static des lien  la presence de mot cle virtual) distructeur de class fille appel auromatiquement le destructeur de la class mere


}

int main(){
    exp031();

    getchar();
    return 0;
}

0

使用模式

class MyClass {
  private: int a;
  public: void setA(int x) { a = x; }
  public: int getA() const { return a; }
};

看起来是面向对象的,具有封装的特性。

然而正如你所注意到的,你仍然可以直接访问私有字段,并没有比将a公开并直接访问它更好。

在C++中使用这样的getter和setter并没有太多意义。


实际上是可以的。例如在C#中,如果你决定缓存对于a的访问(假设计算a需要很多工作),你可以只需将其制作成一个属性即可完成。但是,在C++中,你需要去替换所有引用MyClass.a的代码为MyClass.GetA(); - Billy ONeal
1
这个问题与C++相关,而不是C#。很多人认为为整型提供通用的getter和setter是明智的选择,但事实并非如此。 - Danvil
1
在C++中这样使用getter和setter并没有太多意义。除通过明确定义的接口(例如getter和setter)之外不受限地访问数据成员会使追踪错误变得很困难。您需要查看设置该成员变量的所有位置,以尝试确定为什么它具有意外的值。通过这个明确定义的接口限制对类成员的访问可以使调试变得更加容易,因为您可以获得一些有用的堆栈跟踪信息。 - andand
@andand:或者你可以学会更好地使用调试器。 - John Dibling
这并没有回答问题。这只是对编程风格的个人看法的咆哮(而且结论还错误的事实)。 - SO_fix_the_vote_sorting_bug

0

Getters 和 Setters 并不能完全控制私有数据成员,控制权仍然在父类。


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