青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 2, 文章 - 0, 評(píng)論 - 4, 引用 - 0
數(shù)據(jù)加載中……

在類定義中實(shí)現(xiàn)對(duì)私有數(shù)據(jù)成員的隱藏

上篇文章中,小小展示了下指針的強(qiáng)大威力,也揭示了C++中類的不安全性。

但在實(shí)際應(yīng)用中,如果你寫的類考慮周全,功能完善的話,類的用戶沒有必要通過這種方式來訪問類的私有成員。同時(shí)類的用戶自己也有對(duì)安全的訴求,因此也一般不會(huì)通過此種非正常方式來隨意訪問類的私有成員。

但是,這里又要提到“但是在實(shí)際應(yīng)用中”——你也許無法一次寫出一個(gè)完全可靠的類,不可避免地會(huì)在以后的編碼中逐步對(duì)類進(jìn)行不同程度的修改,有時(shí)甚至?xí)蟮堕煾貏h除多余的成員,增加其他新的成員。這時(shí)頭文件就會(huì)改變,類成員的地址偏移也會(huì)發(fā)生變化。你需要向其他編碼者更新你的頭文件,其他文件中如果用到你的這個(gè)類,那么這些文件就需要重新編譯、連接,很多問題隨之而來。

現(xiàn)在我們要做的就是最大可能地隱藏?cái)?shù)據(jù)成員的細(xì)節(jié),只在頭文件中展示使用這個(gè)類最必要的部分。

聰明的你一定想到另外再定義一個(gè)結(jié)構(gòu)體或類 class MemberData ,把所有數(shù)據(jù)成員都放到 class MemberData 里面,然后在你的類中聲明一個(gè) class MemberData 的對(duì)象作為類的私有數(shù)據(jù)成員。


也許你會(huì)這樣做:

/*
 *    memberdata.hpp
 
*/
#ifndef MEMBERDATA_HPP
#define MEMBERDATA_HPP


class MemberData
{
private:
    
int a;
    
double b;
    
char c;
    
//
    friend class MyClass;
};

#endif // MEMBERDATA_HPP

//////////////////////////////////////////////////////////////////////////

/*
 *    myclass.h
 
*/
#ifndef MYCLASS_H
#define MYCLASS_H
#include 
"memberdata.hpp"

class MemberData;

class MyClass
{
public:
    MyClass();
    
~MyClass();
private:
    MemberData members;
};

#endif // MYCLASS_H

但問題是細(xì)節(jié)隱藏得還不夠深,要提供 myclass.h 必須要連同 memberdata.hpp 一起提供,其他人打開 memberdata.hpp 照樣能看見實(shí)際的數(shù)據(jù)成員。

還有更好的辦法嗎?將 class MemberData 寫在 myclass.cpp 里,甚至直接將整個(gè) class MemberData 作為 class MyClass 的私有類?就像下面這樣:

注意下面的代碼是分成頭文件和實(shí)現(xiàn)文件兩部分的,需要分開放。不然那句 #endif 會(huì)作怪。

/*
 *    myclass.h
 
*/
#ifndef MYCLASS_H
#define MYCLASS_H
#include 
"memberdata.hpp"

class MyClass
{
public:
    MyClass();
    
~MyClass(){};
private:
    
class MemberData;
    MemberData members;
};

#endif // MYCLASS_H

//////////////////////////////////////////////////////////////////////////

/*
 *    myclass.cpp
 
*/

#include 
"myclass.h"

class MyClass::MemberData
{
    
int a;
    
double b;
    
char c;
    
//
    MemberData(int _a=0double _b=0char _c='\0')
        : a(_a)
        , b(_b)
        , c(_c)
    {
    }
};

MyClass::MyClass()
: members(
11'c')
{
}

好,按照我的要求分成兩部分了,但編譯器看到 MemberData members; 這行時(shí)就會(huì)提示使用了未定義的 class MemberData。是的,編譯器不認(rèn)同這樣的代碼,即使我已經(jīng)在前面給出了 class MemberData 的聲明,即使在 myclass.cpp 里我還專門將 class MemberData 的定義放到構(gòu)造函數(shù)前面。

雖然在頭文件里只對(duì) class MyClass 的成員做了聲明,但卻是個(gè)實(shí)實(shí)在在的類定義。編譯器看到類定義就會(huì)考慮確定這個(gè)類中成員的地址偏移,從而進(jìn)一步確定整個(gè)類的大小。而這里的 class MemberData 還是沒有定義的,因此無法確定 members 對(duì)象的大小,那么這個(gè)類型所占用的內(nèi)存空間也是無法確定的。編譯器太心急了,雖然它還未看到  myclass.cpp 中 class MemberData 的定義,雖然 class MyClass 仍然未實(shí)例化,它就已經(jīng)想到以后的事情了。

那么我們考慮將 MemberData members; 這句聲明換成 MemberData* pMembers; 。一個(gè)指針,無論是什么類型,總是占用 4 個(gè)字節(jié)的空間,因此其大小是確定的。

果然,沒有任何的錯(cuò)誤,順利通過編譯和連接。

實(shí)際上很多商業(yè)代碼就是用類似的做法。不過他們更絕,類的其他使用者在頭文件中連 class MemberData 的聲明都看不到,只看到一個(gè) LPVOID pData 。是的,每個(gè)類可能會(huì)包含不同的數(shù)據(jù),但我們只需要一個(gè)指針即可。pData 所指向一個(gè)什么樣的類型無所謂,需要的時(shí)候用 reinterpret_cast 將指針轉(zhuǎn)換到相應(yīng)的類型即可。

但新的問題隨之而來。pMembers (或 pData )未指向任何實(shí)在的內(nèi)存空間,我們必須在構(gòu)造函數(shù)中為  pMembers 分配空間,否則 MyClass 的數(shù)據(jù)成員并不存在。既然分配了空間,那就還要在析構(gòu)函數(shù)中釋放空間。為了穩(wěn)妥,還必須為 class MyClass 編寫拷貝構(gòu)造函數(shù)和賦值函數(shù)。

一個(gè)類沒有什么,但如果每寫一個(gè)類都要這樣做的話,代碼量將劇增。相比以前我們只需要簡單的 private 一下,那可是麻煩多了。可,我是懶人一個(gè)啊。

懶人自有懶人的辦法,而且一定要緊跟流行趨勢(shì)。這幾年流行泛型,我們就用寫個(gè)類模板來實(shí)現(xiàn)想要的功能。

 1 #ifndef IWONG_IMPLEMENT_HPP
 2 #define IWONG_IMPLEMENT_HPP
 3 namespace iwong {
 4 
 5 //////////////////////////////////////////////////////////////////////////
 6 // noncopyable
 7 template<typename tClass> class Implement_noncopyable
 8 {
 9 public:
10     typedef typename tClass element_type;
11     typedef typename element_type* element_type_pointer;
12     typedef typename element_type& element_type_reference;
13     typedef typename element_type const& element_type_const_reference;
14     typedef typename Implement_noncopyable<element_type> this_type;
15     typedef typename this_type& reference;
16     typedef typename this_type const& const_reference;
17 
18 public:
19     Implement_noncopyable() : pImp(NewPtr()) {}
20     ~Implement_noncopyable() { Release(); }
21 
22 public:
23     element_type_pointer get_ptr() { return pImp; }
24     element_type_reference get() { return *pImp; }
25     element_type_const_reference get() const { return *pImp; }
26     element_type_pointer operator->() { return get_ptr(); }
27 
28 protected:
29     Implement_noncopyable(const_reference _other) : pImp(NewPtr(_other)) {}
30 
31     virtual const_reference operator=(const_reference _other)
32     {
33         ValueCopy(_other);
34         return *this;
35     }
36 
37 private:
38     element_type_pointer NewPtr() { return new element_type; }
39     element_type_pointer NewPtr(const_reference _other) { return new element_type(_other.get()); }
40     void ValueCopy(const_reference _ohter) { get() = _ohter.get(); }
41     void Release() { delete pImp; }
42 
43 private:
44     element_type_pointer pImp;
45 };
46 
47 //////////////////////////////////////////////////////////////////////////
48 // copyable
49 template<typename tClass> class Implement : public Implement_noncopyable<tClass>
50 {
51 public:
52     typedef typename const Implement<tClass>& const_reference;
53 
54 public:
55     Implement() : Implement_noncopyable() {}
56     Implement(const_reference _other) : Implement_noncopyable(_other) {}
57 
58     const_reference operator=(const_reference _other)
59     {
60         Implement_noncopyable::operator=(_other);
61         return *this;
62     }
63 };
64 
65 //////////////////////////////////////////////////////////////////////////
66 
67 // namespace iwong
68 
69 #endif // IWONG_IMPLEMENT_HPP

在這個(gè)類模板里,我們封裝了堆空間的分配和釋放,還加上了一些必要的操作。
Implement::get() 返回?cái)?shù)據(jù)類的對(duì)象的引用;
Implement::get() const 返回?cái)?shù)據(jù)類的對(duì)象的常引用;
Implement::get_ptr() 返回?cái)?shù)據(jù)類的指針;
Implement::operator->() 返回?cái)?shù)據(jù)類的指針,是為某些我這樣的懶人準(zhǔn)備的,用的時(shí)候少寫幾個(gè)字母而已。但注意由于這里重載的是 -> 操作符,因此實(shí)際得到的是數(shù)據(jù)類的對(duì)象!于是其功能同 Implement::get() 是一樣的。

class Implement_noncopyable 的對(duì)象除不可拷貝外,其他用法同 class Implement 一樣。

class MyClassImp 的細(xì)節(jié)都隱藏在 cpp 文件中,只要不公開 cpp 實(shí)現(xiàn),從外部是根本沒法進(jìn)行直接訪問的。

下面是一個(gè)使用實(shí)例:

//////////////////////////////////////////////////////////////////
// MyClass.h

#ifndef MYCLASS_H
#define MYCLASS_H
#include 
<Implement.hpp>
using namespace iwong;

class MyClass
{
public:
    MyClass(){}
    
~MyClass(){}

    
int GetA();
    
void SetA();
private:
    
class MyClassImp;
    Implement
<MyClassImp> Imp;
};

#endif // MYCLASS_H


///////////////////////////////////////////////////////////////////
// MyClass.cpp

#include 
"MyClass.h"

MyClass::MyClass()
{}

class MyClass::MyClassImp
{
public:
    
int a;
    
int* b;
    
double c;
    
char d;

    MyClassImp()
        : a(
0)
        , b(
new int(0))
        , c(
0.0)
        , d(
'd')
    {
    }

    
/*
     *    若在 Imp 類中定義了指針,并為其分配了堆空間
     *    在析構(gòu)函數(shù)中仍然需要釋放這個(gè)指針指向的堆空間
     
*/
    
~MyClassImp() { delete b; }
};

int MyClass::GetA()
{
    
return Imp.get().a;
}

void MyClass::SetA(int _a)
{
    Imp
->= _a;
}

需要的注意的是,類模板 Implement 中雖然封裝了堆空間的分配和釋放操作,但這是針對(duì) class MyClassImp 的。而對(duì)于 class MyClassImp 中的數(shù)據(jù)成員,仍然需要自行進(jìn)行空間的分配和釋放,這一點(diǎn)同以前是沒有兩樣的。

posted on 2008-08-11 01:32 iwong 閱讀(1053) 評(píng)論(0)  編輯 收藏 引用


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产一区999| 日韩午夜三级在线| 亚洲午夜高清视频| 久久精品视频导航| 亚洲在线视频网站| 亚洲美女色禁图| 亚洲高清网站| 久久全国免费视频| 国产精品福利在线观看| 欧美日韩一二三区| 欧美激情一区二区三区在线视频| 久久久一本精品99久久精品66| 欧美国产视频日韩| 欧美日本一区二区高清播放视频| 亚洲色无码播放| 一本色道久久综合亚洲精品小说| 日韩视频免费看| 一本一本a久久| 一区二区三区免费网站| 亚洲系列中文字幕| 欧美亚洲网站| 欧美另类视频| 国产综合18久久久久久| 99精品视频免费观看视频| 欧美一级视频免费在线观看| 欧美激情亚洲| 欧美在线播放视频| 欧美日韩成人在线播放| 狠狠色狠狠色综合| 亚洲欧美日本精品| 欧美成人免费在线视频| 性色av一区二区三区| 欧美精品激情在线| 精品不卡在线| 欧美一进一出视频| 亚洲精品黄色| 久久频这里精品99香蕉| 国产精品一国产精品k频道56| 亚洲美女免费视频| 男女av一区三区二区色多| 亚洲伊人色欲综合网| 欧美激情一区二区三区四区| 加勒比av一区二区| 午夜一区二区三视频在线观看 | 国产欧美日韩不卡| 中文日韩电影网站| 亚洲观看高清完整版在线观看| 欧美在线观看www| 国产日韩欧美制服另类| 香蕉免费一区二区三区在线观看 | 亚洲国产精品久久人人爱蜜臀| 午夜在线不卡| 国产精品视频导航| 亚洲网站在线观看| 99精品免费| 国产精品亚发布| 久久亚洲春色中文字幕久久久| 久久免费精品视频| 黑丝一区二区三区| 久久精品五月婷婷| 欧美中文在线字幕| 精品av久久久久电影| 久久只精品国产| 久久久久久999| 在线国产日韩| 亚洲国产精品电影| 欧美日韩精品高清| 欧美亚洲综合在线| 久久久久久久久伊人| 亚洲国产精品第一区二区三区| 欧美高清视频一区| 欧美理论电影网| 亚洲免费视频成人| 久久国产毛片| 亚洲人成网站999久久久综合| 亚洲全黄一级网站| 国产精品视频yy9099| 久久综合九色九九| 欧美精品一区二区高清在线观看| 亚洲一区中文字幕在线观看| 欧美一区二区三区婷婷月色| 亚洲欧洲在线视频| 亚洲一区影院| 亚洲欧洲一区二区天堂久久 | 亚洲午夜精品一区二区| 国产欧美日韩精品一区| 美女精品在线观看| 欧美日韩国产成人在线免费| 香蕉精品999视频一区二区| 欧美在线免费观看| 99riav久久精品riav| 亚洲一区二区三区免费观看| 国产在线精品自拍| 亚洲九九九在线观看| 国产午夜亚洲精品羞羞网站| 欧美激情一级片一区二区| 国产精品成人一区| 欧美成人免费小视频| 国产精品一区二区在线观看不卡 | 欧美一级久久久| 久久综合成人精品亚洲另类欧美| 一本久久综合亚洲鲁鲁| 久久国产精品久久久久久久久久| 日韩小视频在线观看专区| 午夜欧美精品久久久久久久| 99天天综合性| 久久夜色精品国产亚洲aⅴ| 亚洲一区二区三区777| 久久久久久久91| 西西裸体人体做爰大胆久久久| 欧美 日韩 国产 一区| 小黄鸭精品密入口导航| 欧美日韩成人综合| 欧美激情欧美狂野欧美精品| 国精品一区二区三区| 欧美黄色大片网站| 欧美高清视频免费观看| 久久综合亚洲社区| 国产午夜精品久久久久久免费视 | 欧美一区二区性| 一区二区日韩伦理片| 老鸭窝91久久精品色噜噜导演| 久久精品免费观看| 国产精品久久久久久一区二区三区 | 你懂的网址国产 欧美| 久久精品视频在线| 国产精品网站在线观看| 在线视频欧美精品| 一区二区欧美日韩| 欧美激情一二三区| 亚洲欧洲中文日韩久久av乱码| 亚洲第一免费播放区| 久久久免费精品视频| 久久另类ts人妖一区二区| 国产曰批免费观看久久久| 欧美在线网站| 久久久久国产精品一区二区| 国产综合色在线视频区| 久久国产免费| 欧美韩日一区二区| 亚洲精品在线视频| 欧美日韩1080p| 一区二区三区黄色| 亚洲欧美日韩国产一区二区三区| 国产精品高潮久久| 亚欧成人精品| 久久亚洲私人国产精品va| 在线精品亚洲| 欧美激情亚洲另类| 99精品国产福利在线观看免费 | 亚洲精品国产精品国自产在线| 亚洲精品欧美在线| 欧美日韩系列| 亚洲欧美不卡| 久久综合导航| 一本久久知道综合久久| 国产精品免费看| 久久久福利视频| 亚洲国产视频一区| 亚洲一区二区久久| 国产亚洲欧美一区在线观看| 另类尿喷潮videofree | 亚洲国产高清一区二区三区| 欧美韩国日本一区| 亚洲综合大片69999| 蜜乳av另类精品一区二区| 亚洲精品激情| 国产精品一区二区你懂得| 久久久久一区| 亚洲美女在线国产| 久久婷婷一区| 亚洲亚洲精品三区日韩精品在线视频| 免费日韩av电影| 在线综合亚洲| 久久久夜夜夜| 在线午夜精品自拍| 国产一区二区日韩精品欧美精品| 久久精品亚洲精品国产欧美kt∨| 亚洲精品日韩久久| 美女主播精品视频一二三四| 亚洲免费视频中文字幕| 1024成人网色www| 国产精品99免视看9| 麻豆精品在线视频| 欧美亚洲视频在线看网址| 亚洲片区在线| 欧美a级一区| 久久精品av麻豆的观看方式| 一区二区三区成人精品| 在线观看日产精品| 国产欧美一区二区精品秋霞影院| 欧美精品国产一区| 免费不卡欧美自拍视频| 午夜日韩在线| 亚洲一区www| 99精品国产福利在线观看免费| 亚洲国产精品黑人久久久| 久久九九久精品国产免费直播 | 一区二区国产精品| 亚洲精品九九|