相比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. 代码控制 textarea 控件是否为KindEditor 编辑框

    <script charset="utf-8" src="<%:Url.Content("~/UI/Scripts/KindEditor/kinde ...

  2. 内存泄漏 之 MAT工具的使用

    1 内存泄漏的排查方法 Dalvik Debug Monitor Server (DDMS) 是 ADT插件的一部分,其中有两项功能可用于内存检查 : ·    heap 查看堆的分配情况 ·     ...

  3. alsa-lib、alsa-utils移植

    /************************************************************************** * alsa-lib.alsa-utils移植 ...

  4. 《DSP using MATLAB》示例 Example 10.1

    坚持到第10章了,继续努力! 代码: %% ------------------------------------------------------------------------ %% Ou ...

  5. TypeScript学习笔记(六) - 模块

    本篇将介绍TypeScript里的模块,和使用方法. 在ECMAScript 2015标准里,JavaScript新增了模块的概念.TypeScript也沿用了这个概念. 一.模块的导入和导出 模块在 ...

  6. Documentation/filesystems/sysfs.txt 文档翻译--sysfs

    sysfs - 用于导出内核对象的文件系统. 1.sysfs是一个基于ram的文件系统,最初基于ramfs. 它提供了一种方法,可以将内核数据结构,它们的属性以及它们之间的链接导出到用户空间.sysf ...

  7. 安装 Android Studio 2.3 详细过程及错误解决

    因为要开发Android5.0的缘故,抛弃了eclipse转到了Android Studio,第一次使用就是遇到了许多问题,终于是解决问题了,特意写一篇博文给各位要准备从eclipse转到Androi ...

  8. 输入和输出(read,recv,recvmsg...和write,writev,writemsg)

    每一个TCP套接口有一个发送缓冲区,可以用SO_SNDBUF套接口选项来改变这个缓冲区的大小. 应用进程调用 write时,内核从应用进程的缓冲区中拷贝所有数据到套接口的发送缓冲区.如果套接口的发送缓 ...

  9. Eclipse转Android Studio工程实践

    Eclipse转Android Studio工程有两种方式, 一种是兼容Eclipse,两者都可以使用,一种是全新的Android Gradle Project. 这里使用的Android Studi ...

  10. git push 免密码

    git push 免密码 通用情况 使用ssh协议 git add 使用tab键自动补全的中文文件名乱码 jupyter notebook 创建密码 git push 免密码 通用情况 1.使用文件创 ...