我想我知道可以接受,但我不确定我是否能清楚地了解能见度
例如:
class X
{
int x;
};
在这里,'x'仅在课堂上可见,但在课堂外可以访问。如果我是正确的,有人可以在回答中解释关于如何不控制可见性等的文本。?
(C ++ 03 / 11.0)应该注意,它是对成员和基类的访问 被控制,而不是他们的能见度。成员姓名仍然是 对基类的可见和隐式转换仍然存在 当这些成员和基类无法访问时。该 建立对给定构造的解释而不考虑 访问控制。如果建立的解释利用 不可访问的成员名称或基类,构造是 不良形成。
答案 0 :(得分:7)
也许这个例子有帮助:
class Bob
{
private:
int foo(int, int);
};
class David : Bob
{
void goo() {
int a = foo(1, 2); // #1
}
};
class Dani : Bob
{
void foo();
void goo() {
int a = foo(1, 2); // #2
}
};
在第1行,名称foo
可见,但它所指定的功能无法访问(由于对{{{ 1}})。这是一个编译错误,但编译器知道有一个潜在的函数Bob
可以匹配,但是不可访问。
在第2行,名称Bob::foo
仅指foo
,而Dani::foo
不可见(因为它隐藏),因此调用Bob::foo
根本没有匹配函数。这也是一个编译错误,但这次错误是该调用根本没有匹配函数。
答案 1 :(得分:7)
C ++有一些关于私有类成员名称可见性和可访问性的深奥功能。根据定义,私有类成员名称只能由类成员和朋友访问。然而,可见度规则可能会使许多人感到困惑。它们可归纳如下。
在C ++中(“C ++ 03”及更早版本的变体),可访问性和可见性的概念是 独立。类和命名空间的成员只要“在”中就可以看到 范围“并没有从声明的角度降低这种可见性的机制。 可访问性只是类成员的参数,并且与概念正交 能见度。后一种观察对于新手C ++程序员来说经常是令人惊讶的。请参阅此PDF。
请考虑以下示例。
#include < complex>
class Calc
{
public:
double Twice( double d );
private:
int Twice( int i );
std::complex Twice( std::complex c );
};
int main()
{
Calc c;
return c.Twice( 21 ); // error, Twice is inaccessible
}
当编译器必须解析对函数的调用时,它按顺序执行三个主要操作:
在执行任何其他操作之前,编译器会搜索范围 至少有一个名为Twice的实体,并列出候选人名单。 在这种情况下,名称查找首先查看Calc的范围以查看是否 至少有一个名为Twice的函数;如果没有,基地 将依次考虑类和封闭的命名空间,一个在a 时间,直到找到至少有一个候选人的范围。在这 但是,编译器看起来已经具有的第一个范围 一个名为Twice的实体 - 事实上,它有三个,所以 三人成为候选人。 (有关名称的更多信息 在C ++中查找,讨论它如何影响你的方式 应打包您的类及其接口
接下来,编译器执行重载决策以选择唯一 候选人名单中的最佳匹配。在这种情况下,论证 是21,这是一个int,可用的重载需要一个双,一个 int和一个复杂的。显然,int参数是最佳匹配 int参数(它是完全匹配,没有转换 需要),所以选择了两次(int)。
最后,编译器执行可访问性检查以确定 是否可以调用所选择的功能。
请注意,辅助功能(由C ++中的修饰符定义)和可见性是独立的。可见性基于C ++的范围规则。类成员可以同时可见和无法访问。
静态成员作为示例在运行应用程序时全局可见,但仅可访问仅适用于应用于它们的修饰符。
答案 2 :(得分:1)
作为注释:当您声明class
时,默认情况下范围是私有的(与struct
相对,默认情况下成员是公共的。)
变量成员'x'只能由您的班级及其朋友访问。没有其他人可以直接访问'x'(如果你有一个函数返回对它的引用,它可以间接访问它,这是一个非常糟糕的主意。)
您引用的文字讨论了编译器的可见性,因此X::x
存在,无论如何。它不会消失只是因为它是私有的。可见性用于查找您引用的成员,并返回匹配的第一个成员。此时,编译器会检查可访问性,如果可访问,那么一切都很好。如果不是格式错误。
请注意,我提到了朋友。该关键字使所有变量成员都可访问。当编译器与朋友交易时,它会完全忽略所有受保护和私有关键字。
在大多数情况下,这是一个非常简单的过程。它按顺序排列。周期。
当你开始使用虚函数变得更复杂时:这些可以是公共的,受保护的和私有的,并且可以根据类声明而改变...(A派生自B并将受保护的虚拟函数公开;它通常不是一个好主意,但C ++并不会阻止你这样做。)当然这只适用于函数,而不是变量成员,所以这是一个不同的主题。
答案 3 :(得分:0)
可访问性和可见性是独立的,这在以下情况下尤其令人困惑:
class A
{
public:
void Foo(int i){
}
};
class B : public A
{
private:
void Foo(){
}
};
int main(){
B b{};
b.Foo(12);
}
其他语言的程序员希望A::Foo(int)
是可调用的,因为它是公共的。这里的重点是,私有B::Foo
隐藏了继承的proc。
这可以通过使用声明using A::Foo
来解决。但是在这种情况下真的变得很困难:
class A
{
public:
void Foo(int i){
}
};
class B : public A
{
public:
using A::Foo;
private:
void Foo(){
}
};
class C : public B
{
public:
using B::Foo;
private:
void Foo(char c){
}
}
int main(){
B b{};
b.Foo(12);
}
使用要求没有私有功能。 AFAIK解决此问题的最佳方法是为私有或受保护的函数(例如do_XXX()或do_XXX_internal)使用一些前缀/后缀。
在STL中,私有成员通常以单个下划线作为前缀(这些是保留的标识符)。