内联类函数及其私有数据成员

10

我现在正在学习关于内联函数的知识,遇到一些让我困惑的事情。

看这个类:

class Nebla{
private:
    int x;
public:
    inline void set(int y){x=y;}
    inline void print(){cout<<x<<endl;}
};

它有一个私有数据成员:int x;

同时它有两个公共的内联函数:set(int y)print()

由于这两个函数是内联的,当它们被调用时,编译器会将函数调用替换为函数内容。

因此,如果我这样做:

Nebla n;
n.set(1);
n.print();

由于这两个函数都是内联的,因此它应该等同于这个:
Nebla n;
n.x=1;
cout<<n.x<<endl;

但是等一下,x 是私有的。因此,这应该不起作用。

但它确实起作用了,我很困惑为什么它会起作用,虽然通常你不能从类外访问私有成员?

有人能解释一下为什么你可以从类外访问私有数据成员,但当成员函数是内联时,它可以,尽管内联只是用函数内容替换函数调用吗?


内联不仅仅是 n.x=1;。你的假设是错误的。 - Mahesh
4个回答

12

数据成员保护只是一个概念性的东西,存在于编译器级别。编译器在翻译源代码时会检查并执行访问控制。一旦代码被编译,公有和私有数据成员之间就没有区别了,即没有物理机制来强制访问控制并防止对私有数据成员的访问。

成员访问是根据语言规范由编译器执行的。语言规范规定,类成员函数(无论是否内联)可以访问类的私有成员。因此编译器允许该访问。与此同时,其他函数被禁止这样的访问,因此编译器会报错。

在您的示例中,您正在从成员函数中访问私有数据成员。这是允许的,因此代码可以编译通过,即编译器不会报错。生成的机器代码在函数被内联后发生的事情完全无关紧要。就是这样。


你有证据证明你所说的吗? - Mohamed Ahmed Nabil
@Mohamed Ahmed Nabil:这就像是让我提供2+2=4的参考一样。一方面,当然,我有一个参考:语言规范或几乎任何关于C++的基础书籍。另一方面,这个问题非常基础,以至于很难在这种情况下选择最好的参考资料。就把我自己看作那个参考吧 :) - AnT stands with Russia
@MohamedAhmedNabil:你可以通过交错使用privateprotectedpublic数据成员并查看它们的地址来自我证明。你可以通过从函数返回指向private数据成员的指针,然后通过这些指针进行操作来自我证明。 - David Schwartz
此外,如果函数签名中有关键字“inline”,编译器并不一定要将函数内联。 - Rjain

6
你误解了inline的工作方式。编译器会内联代码的逻辑,而不是代码的实际文本。
因为函数的内容就是函数的内容。即使进行了内联,它们仍然是函数的一部分。在成员函数内部可以访问私有成员变量。当成员函数被内联时,其代码仍然在成员函数内部,因为函数被内联了。

嗯...那有点解释清楚了,谢谢。我想我的书里的解释不够清晰。 - Mohamed Ahmed Nabil
被内联的不是函数的内容,而是函数的含义(即其行为)。 - David Schwartz

2

首先,是否进行内联取决于编译器。在许多情况下,它会决定不这样做。

其次,如果进行了内联,则会使用由C ++源代码描述的行为生成的编译二进制产品进行内联,而不是实际文本。


0

Morbo说inline关键字不起作用。

Morbo说,inline关键字表示应该忽略涉及此函数的符号冲突(symbol conflict),并且所有实现在类声明内的函数都隐式为inline。

Morbo很聪明,你应该听他的话,即使inline还有一个涉及获取地址的次要技术含义。

更严肃地说,inline只是让你将实现定义放入头文件中。因此,使代码成为内联代码更容易,因为它不必在链接时发生(大多数C++链接器太懒了),但它并不会导致代码成为内联代码。

最后,隐私是概念性的,它不受C++运行时强制执行。它只是在编译时通过告诉您某些内容越界来进行强制执行。


你好,Morbo。家人们怎么样? - David Schwartz
Morbo说好斗且众多。 - Yakk - Adam Nevraumont

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