相比C语言,C++中通过class/struct来定义既包含数据,又包含行为的结构,从而支持了“对象”。现实世界中,一个人(一个对象)通常 拥有一些资产(数据),并且掌握某些技能(行为),并且这些资产和技能通常可以分为三类:

  1. 可以与任何人分享的
  2. 有限分享的,比如留给子孙后代的财产或本领
  3. 除了自己之外谁也不能用的,比如给自己留的棺材^_^

为了表达类似的概念,在C++中使用public、protected以及private,分别代表可任意分享的、有限分享的以及独享的。比现实世界稍微复杂些,在C++中这三个关键字不仅可以修饰类成员,还可以修饰类的继承关系。

当这三个关键字用在类成员时:

class Base
{
public:
void publicMethod()
{
cout << "Begin of " << __FUNCTION__ << endl;
cout << "End of " << __FUNCTION__ << endl;
} static void staticPublicMethod(Base* obj)
{
// just call this class's static private method
staticPrivateMethod(obj);
} int getProperty() { return property_; }
protected:
void protectedMethod()
{
cout << "Begin of " << __FUNCTION__ << endl;
cout << "call publicMethod from protected method: " << endl;
publicMethod();
cout << "End of " << __FUNCTION__ << endl;
}
private:
void privateMethod()
{
cout << "Begin of " << __FUNCTION__ << endl; cout << "call publicMethod from private method: " << endl;
publicMethod(); cout << "call protected method from private method: " << endl;
protectedMethod(); cout << "End of " << __FUNCTION__ << endl;
} static void staticPrivateMethod(Base* obj)
{
// ok
obj->publicMethod(); // ok
obj->protectedMethod(); // ok
obj->privateMethod();
} int property_;
}; class Derived : public Base
{
public:
void accessBase()
{
cout << "In Derived::" << __FUNCTION__ << ": " << endl;
cout << "we can access Base's public method:" << endl;
publicMethod(); cout << "we can access Base's protected method too: " << endl;
protectedMethod(); cout << "but we can't access Base's private method!" << endl;
// we will get a compile error if we try to call privateMethod: 'privateMethod' is a private member of 'Base'
// privateMethod();
} static void staticDerivedMethod(Derived* obj)
{
// ok
obj->protectedMethod(); // compile error: 'privateMethod' is a private member of 'Base'
// obj->privateMethod();
}
}; int main()
{
Base obj;
// ok
obj.publicMethod(); // compile error: 'protectedMethod' is a protected member of 'Base'
// obj.protectedMethod(); // compile error: 'privateMethod' is a private member of 'Base'
// obj.privateMethod(); // ok
Base::staticPublicMethod(&obj); Derived dobj;
// ok
dobj.accessBase(); // ok
Derived::staticDerivedMethod(&dobj);
return 0;
}

从上面的程序中,可以看出:

  1. 用public修饰的成员,既可以在其类内部使用(在privateMethod中调用),也可以在类外部通过类的实例来访问(main函数中调用obj.publicMethod())
  2. 用protected修饰的成员,能在该类内部或者其派生类(严格上说是非私有继承的派生类,下面会详细介绍)中使用(见privateMethod、accessBase以及staticDerivedMethod)
  3. 用private修饰的成员,仅能在该类内部使用,在类外部或者派生类中都不能使用。

注意:以上描述中的“使用”,指的是直接引用(如不能在Derived中直接调用privateMethod)。尽管不能直接引用,但是仍然可以通过其他方法来访问(虽然在 Derived中无法直接访问Base的property_,但通过getProperty(),我们仍然可以在需要的时候获取其值)。

除了可以修饰类成员,这三个关键字还可以修饰类的继承关系:

class Base
{
public:
void publicBaseMethod()
{
cout << __FUNCTION__ << endl;
}
protected:
void protectedBaseMethod()
{
cout << __FUNCTION__ << endl;
}
private:
void privateBaseMethod()
{
cout << __FUNCTION__ << endl;
}
}; // public inheritance, all Base's members remain the same scope
class PublicDerived : public Base
{
public:
void accessBase()
{
// ok
publicBaseMethod(); // ok
protectedBaseMethod(); // compile error: 'privateBaseMethod' is a private member of 'Base'
// privateBaseMethod();
}
}; // protected inheritance, Base's public members will become protected in ProtectedDerived
class ProtectedDerived : protected Base
{
public:
void accessBase()
{
// ok
publicBaseMethod(); // ok
protectedBaseMethod(); // compile error: 'privateBaseMethod' is a private member of 'Base'
// privateBaseMethod();
}
}; // private inheritance, Base's public and protected members will become private in PrivateDerived
class PrivateDerived : private Base
{
public:
void accessBase()
{
// ok
publicBaseMethod(); // ok
protectedBaseMethod(); // compile error: 'privateBaseMethod' is a private member of 'Base'
// privateBaseMethod();
}
}; class SonOfPrivateDerived : public PrivateDerived
{
public:
void accessParent()
{
// compile error: 'publicBaseMethod' is a private member of 'Base'
// publicBaseMethod(); // compile error: 'protectedBaseMethod' is a private member of 'Base'
// protectedBaseMethod(); // IMPORTANTE NOTE: why PrivateDerived can access publicBaseMethod and protectedBaseMethod,
// although they are both private members of 'Base'??? // compile error: 'privateBaseMethod' is a private member of 'Base'
// privateBaseMethod();
}
}; int main()
{
PublicDerived pubd;
// ok
pubd.publicBaseMethod(); // compile error: 'protectedBaseMethod' is a protected member of 'Base'
// pubd.protectedBaseMethod(); // compile error: 'privateBaseMethod' is a private member of 'Base'
// pubd.privateBaseMethod(); pubd.accessBase(); ProtectedDerived prod;
// compile error: 'publicBaseMethod' is a protected member of 'Base',
// NOTE: the Base's public members now become protected in ProtectedDerived's perspective
// prod.publicBaseMethod(); // compile error: 'protectedBaseMethod' is a protected member of 'Base'
// NOTE: The Base's protected members remain protected in ProtectedDerived's perspective
// prod.protectedBaseMethod(); // compile error: 'privateBaseMethod' is a private member of 'Base'
// NOTE: The Base's private members remain private in ProtectedDerived's perspective
// prod.privateBaseMethod(); prod.accessBase(); PrivateDerived prid;
// compile error: 'publicBaseMethod' is a private member of 'Base'
// NOTE: publicBaseMethod now become private in PrivateDerived's perspective
// prid.publicBaseMethod(); // compile error: 'protectedBaseMethod' is a private member of 'Base'
// NOTE: protectedBaseMethod also become private in PrivateDerived's perspective
// prid.protectedBaseMethod(); // compile error: 'privateBaseMethod' is a private member of 'Base'
// prid.privateBaseMethod(); prid.accessBase(); SonOfPrivateDerived pubprid;
// NOTE: check the comments in accessParent to get the point
pubprid.accessParent(); return 0;
}

根据以上程序,可以得出public、protected和private在修饰继承关系中的作用为:

  1. 当使用公有继承(public Base)时,派生类中看到的基类成员属性与基类中定义的一致,如示例程序中publicBaseMethod、protectedBaseMethod和privateBaseMethod仍然分别为public、protected和private
  2. 当使用保护继承(protected Base)时,派生类中看到的基类的成员属性与基类定义不一致,原来基类中的public成员在派生类中被认为是基类的protected成员了,如示例中无法通过ProtectedDerived类的实例在类外部调用publicBaseMethod
  3. 当使用私有继承(private Base)时,派生类中看到的基类成员属性同样与基类定义不一致,即原来基类中的public和protected成员在派生类中都被当成了private成员了,如示例中只能在PrivateDerived类内部调用publicBaseMethod和protectedBaseMethod
  4. 在私有继承中,尽管当在外部调用public或protected成员时,其出错信息(通过clang++编译得到的)都是“'xxx' is a private member of 'Base'”,事实上并非如此:在私有继承关系中,基类的public和protected成员并非被当做基类的私有成员了,而是被当做派生类的私有成员了。如果是被当做是基类的私有成员,那么PrivateDerived中是无法访问publicBaseMethod和protectedBaseMethod的;但实际上,从PrivateDerived中可以访问publicBaseMethod和protectedBaseMethod,而SonOfPrivateDerived中无法访问它们,因此publicBaseMethod和protectedBaseMethod应该是PrivateDerived的私有成员而非Base的私有成员。

Author: Rex Shen

Created: 2014-02-16 Sun 08:24

Emacs 24.3.1 (Org mode 8.2.5h)

Validate

C++中public、protected以及private的使用的更多相关文章

  1. java中public protected friendly private作用域

    1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直 ...

  2. C++中public,protected,private派生类继承问题和访问权限问题

    C++中public,protected,private派生类继承问题和访问权限问题 当一个子类从父类继承时,父类的所有成员成为子类的成员,此时对父类成员的访问状态由继承时使用的继承限定符决定. 1. ...

  3. java中的 public protected friendly private

    1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直 ...

  4. public,protected,friendly,private的访问权限

    请说出作用域public,private,protected,以及不写时的区别 这四个作用域的可见范围如下表所示. 说明:如果在修饰的元素上面没有写任何访问修饰符,则表示friendly. 作用域   ...

  5. java 修饰符的作用一(public protected default private 组)

    1.public protected default private 组 public 权限最大,同类,同包,不同包,同包子类父类之间,不同包子类父类之间都可以访问. java 默认的权限是defau ...

  6. Java访问权限修饰符public protected friendly private用法总结(转载好文Mark)

    首先声明:Java中,friendly这个修饰符并没有显式的声明,在成员变量和方法前什么修饰符也不用,默认的就是friendly.为了条理清晰,分三种不同情况来总结. 一 访问权限修饰符修饰成员变量和 ...

  7. Java学习笔记(4)----Public,Protected,Package,Private修饰符可见性

    Java修饰符类型(public,protected,private,friendly) public的类.类属变量及方法,包内及包外的任何类均可以访问:protected的类.类属变量及方法,包内的 ...

  8. 【java基础】(1)Java的权限修饰符(public,protected,default,private)

    访问权限修饰符权限从高到低排列是public  ,protected  ,default, private. 一.根据“是否是同包”.“是否是子类”分为4中情况+本类 5种情况 二.把 同包中的子类 ...

  9. java四种权限修饰符(public > protected > (default) > private)

    权限修饰符在哪里可以访问 (default) : 表示什么权限修饰符都不写 位置 public protected (default) private 同一个类 yes yes yes yes 同一个 ...

  10. 【转载】C++中public,protected,private访问

    第一:private, public, protected 访问标号的访问范围. 假如我们约定: 类内部-----指的是当前类类型的定义中,以及其成员函数的声明和定义中: 类外部-----指的是不在当 ...

随机推荐

  1. Linux运维学习笔记-文件权限知识总结

    权限总结: 1. 可读r:表示具有读取\阅读文件内容的权限: 2. 可写w:表示具有新增.修改文件内容的权限: a. 若果没有r配合,那么vi编辑文件会提示无法编辑(但可以强制编辑),echo可以重定 ...

  2. ubuntu 11.04 Gnome 恢复默认的任务栏面板

    在Ubuntu(实际是GNOME) 中,桌面上默认的任务栏菜单面板是上下两栏,上面(Panel) 是系统菜单和通知区域下面是窗口存放切换区域,那么作为ubuntu用户来说,你总会使系统用起来更顺手更美 ...

  3. MarkDown格式作业模板

    发布的随笔可复制下面的MarkDowm模板 注意事项 标题第XX次作业替换成相应的第一次作业.第二次作业...... 代码托管的链接一定要换成自己的项目 码云提交历史截图必须是自己每周的提交截图 #& ...

  4. 使 docker 容器可以正常 mount privileged

    [docker]privileged参数 privileged参数   $ docker help run ... --privileged=false Give extended privilege ...

  5. springboot整合mybatis增删改查(三):mybatis逆向工程

    上一篇已经把项目基本框架完善,接下来就是利用Mybatis Generator逆向工程进行mybatis的整合. 我们在创建项目开始的时候已经勾选web,mybatis,sql等,但是这些依赖还是不够 ...

  6. 20155202 2016-2017-2 《Java程序设计》第8周学习总结

    20155202 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 有Java.util.logging包提供了日志功能相关类与接口,使用日志起点是logger ...

  7. springboot将项目打成war包

    1. 将项目的打包方式改为war包 <groupId>com.cc</groupId> <artifactId>aaaaaa</artifactId> ...

  8. Libusb学习

    1.参考:http://www.cnblogs.com/Daniel-G/archive/2013/04/22/3036730.html https://baike.so.com/doc/506541 ...

  9. 静态链接ffmpeg库注意的问题(转)

    1. 最近使用ffmpeg静态库进行链接,提示 undefined reference,排查发现静态库的顺序导致的,静态库对先后顺序有严格要求 2. 使用ffmpeg库时,在链接时,需要加上-lm - ...

  10. bzoj 3924 [Zjoi2015]幻想乡战略游戏——动态点分治(暴力移动找重心)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3924 度数只有20,所以从一个点暴力枚举其出边,就能知道往哪个方向走. 知道方向之后直接走到 ...