以下是我在源文件source.cpp中的代码:
class B
{
friend class F;
protected:
int protectedIntB;
};
class D : public B {};
class F
{
public:
int f(D &d) {return ++d.protectedIntB;}
};
当我使用g++ -c -Wall -pedantic -std=c++11 source.cpp
和cl /c source.cpp
编译上述代码时,两个编译器都成功编译。但是,当我使用protected
代替public
而使B继承自B时
class D : protected B {};
这一次,gcc成功编译,而cl给出错误,表示B::protectedIntB
中return ++d.protectedIntB;
无法访问。
另一种情况是将public
替换为private
:
class D : private B {};
这次,两个编译器都会产生错误。顺便说一下,我使用mingw-w64构建的gcc 5.3.0版本和VS2015的cl版本19.00.24210。
我的问题出现了:
基类的友元类如何通过从基类派生的类的对象访问该基类的成员,以及为什么gcc和cl以不同的方式处理它?</ p>
修改
感谢songyuanyao和Brian,这似乎是protected
案例中gcc 5.3.0中的错误。只有public
案例才能成功编译,gcc 6.1.0也可以正常编译。
答案 0 :(得分:3)
根据[class.access.base] / 5:
对会员的访问受到影响 由成员命名的类。此命名类是成员名称所在的类 抬头找到了。
根据[class.access.base] / 6:
如果使用类成员访问运算符(包括隐式“
this->
”)来访问非静态数据成员 或非静态成员函数,如果左操作数(被认为是指针中的指针),则引用是错误的 “.
”运算符case)不能隐式转换为指向右操作数命名类的指针。
因此,在您的特定情况下,为了访问d.protectedIntB
,必须满足以下两个条件:
您必须有protectedIntB
成员B
才能访问B
,因为protectedIntB
是找到名称B
的类。 (注意:这可以通过使用 using-declaration; 重新声明派生类中的成员来改变,在这种情况下派生类将控制它。)
您必须有权D
作为D*
的基础,即能够将B*
转换为B
}。如果D
是B
的公共基础,那很好。如果D
是F::f
的受保护基础,则会应用访问权限检查,F
失败,因为D
不是D
的朋友且不是派生的等级 public class discount {
int quantity;
double price;
public static int NINETY_NINE = 99;
public static int TWENTY = 20;
private static int TEN = 10, FORTY_NINE = 49;
public static double TEN_PERCENT = 0.10, FIVE_PERCENT = 0.05,
TWO_PERCENT = 0.02, THREE_PERCENT = 0.03, ONE_PERCENT = 0.01 ;
private double discount;
// public static double discount_amount = discount * quantity * price;
discount(int quantity, double price)
{
double discount = 0;
//double d = discount;
this.quantity = quantity;
this.price = price;
}
boolean quantityOutOfRange()
{
return quantity < 0;
}
boolean priceOutOfRange()
{
return price < 0;
}
public double getDiscount()
{
return discount;
}
public int getQuantity()
{
return quantity;
}
public double getUnitPrice()
{
return price;
}
public void calculate()
{
if (quantity > NINETY_NINE)
{
if (price > TWENTY)
discount = TEN_PERCENT;
else if ( price > TEN)
discount = FIVE_PERCENT;
else
discount = TWO_PERCENT;
}
else if (quantity > FORTY_NINE)
{
// calculate discount
if (price > TWENTY)
discount = THREE_PERCENT;
else if ( price > TEN)
discount = TWO_PERCENT;
else
discount = ONE_PERCENT;
}
else
{
// calculate discount
if (price > TWENTY)
discount = TWO_PERCENT;
else if ( price > TEN)
discount = ONE_PERCENT;
else
discount = 1;
}
if (quantity < 0)
{
System.out.println("Quantity is negative. Cannot compute discount");
}
//double discount_amount = discount * quantity * price;
}
}
public class TestDiscount {
public static void main(String[] arg) {
String input = JOptionPane.showInputDialog("Enter the quantity desired "
+ ", and unit price "
+ "\n(Separated by spaces)");
Scanner in = new Scanner(input);
int quantity = in.nextInt();
double price = in.nextDouble();
discount current = new discount(quantity, price);
current.calculate();
System.out.println("\nDiscounts:\n");
System.out.println("The quantity is: " + current.getQuantity()+ "\tThe unit price is = $ " + current.getUnitPrice() +
"\tThe discount is = $ " + current.getQuantity()* current.getUnitPrice() * current.getDiscount());
System.exit(0) ;
}
}
。
令人惊讶的是,GCC似乎是编译器在受保护的情况下是错误的但是这个错误appears fixed。请注意,Clang提供much better diagnostic。
答案 1 :(得分:3)
如果使D
继承自B
使用protected或private而不是public,则编译应该失败。
从标准$11.2/5 Accessibility of base classes and base class members [class.access.base]:
开始如果
,则在N类中命名时,可以在R点访问成员m(5.4)存在可在R处访问的N的基类B. 当在B组中命名时,可以在R访问m。[例如:
class B; class A { private: int i; friend void f(B*); }; class B : public A { }; void f(B* p) { p->i = 1; // OK: B* can be implicitly converted to A*, // and f has access to i in A }
- 结束示例]
对于第一种情况,B
的基类D
可在F::f()
访问,因为它是公共继承。 B::protectedIntB
可以访问F::f()
,因为它是班级B
的朋友。
如果将其更改为受保护或私有继承,则B
的基类D
无法再次在F::f()
访问,则编译将失败。注意F::f()
不是派生类D
的朋友。这意味着如果你把它作为类D
的朋友,编译就会成功。
BTW:我尝试使用gcc here进行受保护的继承,但失败了。
答案 2 :(得分:0)
如果代码在gcc 5.3.0上编译并且不在cl上编译,则概率很高,其中一个不严格执行C ++标准。如果我必须猜测,对于受保护和私有继承,您应该得到编译器错误。有关不同类型的继承之间的差异,请参阅Difference between private, public, and protected inheritance以获取更多详细信息。
为了使F类能够访问B类的私有成员,它应该知道D类派生自B类,它只会发生在公共继承中。