最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何在C++類的外部調(diào)用類的私有方法

 更新時(shí)間:2022年09月09日 10:45:15   作者:ithiker  
這篇文章主要介紹了如何在C++類的外部調(diào)用類的私有方法,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下

前言

可否在C++類的外部調(diào)用類的私有方法呢?既然談到了這個(gè)問題,當(dāng)然是可以的。

問題

目標(biāo)是在一個(gè)外部function中調(diào)用Widget::forbidden()這個(gè)private function。限制條件是不能修改Widget類。

class Widget {
   private:
    void forbidden();
  };
void hijack(Widget& w) {
    w.forbidden();  // ERROR!
  }

下面我們一步步來實(shí)現(xiàn)這個(gè)小目標(biāo):

技術(shù)準(zhǔn)備

顯然,我們不可能直接像w.forbidden()類似那樣調(diào)用,我們必須通過PMF(pointer to member function)來間接調(diào)用,所以,下面先簡(jiǎn)要介紹PMF:

1. pointers to member functions

由于下面會(huì)廣泛的用到pointers to member functions (PMFs),我們先來回顧一下它的用法:

class Calculator {
  float current_val = 0.f;
 public:
   void clear_value() { current_val = 0.f; };
   float value() const {
     return current_val;
   };

   void add(float x) { current_val += x; };
   void multiply(float x) { current_val *= x; };
};

在C++11中,使用函數(shù)指針調(diào)用函數(shù),我們可以這么做:

  using Operation = void (Calculator::*)(float);
 
  Operation op1 = &Calculator::add;
  Operation op2 = &Calculator::multiply;
  
  using Getter = float (Calculator::*)() const;
  Getter get = &Calculator::value;
  
  Calculator calc{};
  (calc.*op1)(123.0f); // Calls add
  (calc.*op2)(10.0f);  // Calls multiply
  // Prints 1230.0
  std::cout << (calc.*get)() << '\n';

函數(shù)指針的一個(gè)特性是它可以綁定到類的是由成員函數(shù),下面我們將會(huì)用到這點(diǎn),假設(shè)Widget類提供了某種機(jī)制來獲取其私有成員函數(shù)的方法,那么,實(shí)現(xiàn)我們的目標(biāo)就可以像下面這樣做:

class Widget {
 public:
  static auto forbidden_fun() {
    return &Widget::forbidden;
  }
 private:
  void forbidden();
};

void hijack(Widget& w) {
  using ForbiddenFun = void (Widget::*)();
  ForbiddenFun const forbidden_fun =
    Widget::forbidden_fun();

  // Calls a private member function on the Widget
  // instance passed in to the function.
  (w.*forbidden_fun)();
}

采用這種辦法不錯(cuò),但是別忘了,我們不能修改Widget類,大多數(shù)的類也不提供返回私有成員的方法。

既然我們不能通過添加函數(shù)返回PMF的方法來進(jìn)行實(shí)踐,那么,是否還有其它方法可以在類的外部訪問類的私有成員呢?C++提供了顯式模板特化的方法。

2. The explicit template instantiation

C++ 標(biāo)準(zhǔn)中提到:

17.7.2 (item 12)
The usual access checking rules do not apply to names used to specify explicit instantiations. [Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible.]

顯式模板特化時(shí),名字訪問規(guī)則此時(shí)不起作用,Stack Overflow 給出了一個(gè)例子:

class Foo
{
private:
  struct Bar;

  template<typename T> class Baz { };

public:
  void f();  // does things with Baz<Bar>
};

// explicit instantiation declaration
extern template class Foo::Baz<Foo::Bar>;

這里在顯式模板特化Foo::Baz時(shí),可以訪問Foo::Baz和Foo::bar

到這里,既然成員訪問規(guī)則不適用于模板特化,模板特化時(shí)可以訪問類的私有成員,那么,我們可否將PMF作為模板參數(shù)呢,下面將介紹這點(diǎn)。

3. Passing a member-function pointer as a non-type template parameter

在C++中模板參數(shù)通常分為兩類:

  • 類型參數(shù),一般的參數(shù)都是類型參數(shù),用來進(jìn)行類型替換;
  • 非類型參數(shù),常見的是整型或指針類型的非類型參數(shù)

比如下面,其中T是類型參數(shù),size是非類型參數(shù):

template <class T, int size> // size is the non-type parameter
class StaticArray
{
private:
    // The non-type parameter controls the size of the array
    T m_array[size];
 
public:
    T* getArray();
	
    T& operator[](int index)
    {
        return m_array[index];
    }
};

下面我們?cè)倏匆粋€(gè)指針作為非類型參數(shù)的例子:

class SpaceShip {
 public:
  void dock();
  // ...
};

// Member function alias that matches the
// signature of SpaceShip::dock()
using SpaceShipFun = void (SpaceShip::*)();

// spaceship_fun is a pointer-to-member-function
// value which is baked-in to the type of the
// SpaceStation template at compile time.
template <SpaceShipFun spaceship_fun>
class SpaceStation {
  // ...
};

// Instantiate a SpaceStation and pass in a
// pointer to member function statically as a
// template argument.
SpaceStation<&SpaceShip::dock> space_station{};

上面的別名SpaceShipFun的使用使得SpaceStation只能用SpaceShip::dock的PMF來實(shí)例化,這個(gè)模板顯得不那么通用,所以我們可以將函數(shù)指針也作為一個(gè)模板參數(shù):

template <
  typename SpaceShipFun,
  SpaceShipFun spaceship_fun
>
class SpaceStation {
  // ...
};

// Now we must also pass the type of the pointer to
// member function when we instantiate the
// SpaceStation template.
SpaceStation<
  void (SpaceShip::*)(),
  &SpaceShip::dock
> space_station{};

當(dāng)然,我們也可以更進(jìn)一步,在實(shí)例化模板的時(shí)候讓編譯器自動(dòng)推導(dǎo)函數(shù)指針的類型:

 SpaceStation<
    decltype(&SpaceShip::dock),
    &SpaceShip::dock
  > space_station{};

到這里,我們似乎找到了解決方案,通過顯示模板特化導(dǎo)出本來對(duì)外部不可見的函數(shù)指針,通過函數(shù)指針調(diào)用是由函數(shù)

4. Solution. Passing a private pointer-to-member-function as a template parameter

我們結(jié)合上面的3個(gè)技巧,似乎找到了解決方案:

// The first template parameter is the type
// signature of the pointer-to-member-function.
// The second template parameter is the pointer
// itself.
template <
  typename ForbiddenFun,
  ForbiddenFun forbidden_fun
> struct HijackImpl {
  static void apply(Widget& w) {
    // Calls a private method of Widget
    (w.*forbidden_fun)();
  }
};

// Explicit instantiation is allowed to refer to
// `Widget::forbidden` in a scope where it's not
// normally permissible.
template struct HijackImpl<
  decltype(&Widget::forbidden),
  &Widget::forbidden
>;

void hijack(Widget& w) {
    HijackImpl<
      decltype(&Widget::forbidden),
      &Widget::forbidden
    >::apply(w);
  }

運(yùn)行一下,發(fā)現(xiàn)其實(shí)不可行:

error: 'forbidden' is a private member of 'Widget'
   HijackImpl<decltype(&Widget::forbidden),
     &Widget::forbidden>::hijack(w);

主要的原因是因?yàn)樵趆ijack函數(shù)中使用HijackImpl<decltype(&Widget::forbidden), &Widget::forbidden>::apply(w)不是顯式模板特化,它只是常見的隱式模板實(shí)例化。

那么,如何采用顯示模板特化的方法你?這就需要使用friend技巧:

5. Friend

我們通常這樣定義和使用友員函數(shù):

class Gadget {
  // Friend declaration gives `frobnicate` access
  // to Gadget's private members.
  friend void frobnicate();

 private:
  void internal() {
    // ...
  }
};

// Definition as a normal free function
void frobnicate() {
  Gadget g;
  // OK because `frobnicate()` is a friend of
  // `Gadget`.
  g.internal();
}

但是不會(huì)這樣:

class Gadget {
  // Free function declared as a friend of Gadget
  friend void frobnicate() {
    Gadget g;
    g.internal(); // Still OK
  }

 private:
   void internal();
};

void do_something() {
  // NOT OK: Compiler can't find frobnicate()
  // during name lookup
  frobnicate();
}

因?yàn)閒robnicate在Gadget內(nèi)部,do_something()在做名字查找時(shí)不會(huì)查找到frobnicate,解決辦法如下:

class Gadget {
  friend void frobnicate(Gadget& gadget) {
    gadget.internal();
  }

 private:
   void internal();
};

void do_something(Gadget& gadget) {
  // OK: Compiler is now able to find the
  // definition of `frobnicate` inside Gadget
  // because ADL adds it to the candidate set for
  // name lookup.
  frobnicate(gadget);
}

當(dāng)然如果do_something不帶參數(shù),我們?cè)谕獠恐匦侣暶饔褑T函數(shù),也是可以的:

class Gadget {
  // Definition stays inside the Gadget class
  friend void frobnicate() {
    Gadget g;
    g.internal();
  }

 private:
   void internal();
};

// An additional namespace-scope declaration makes
// the function available for normal name lookup.
void frobnicate();

void do_something() {
  // The compiler can now find the function
  frobnicate();
}

了解了這些,對(duì)下面這樣的代碼就不會(huì)太吃驚了:

#include <iostream>

template <int N>
class SpookyAction {
  friend int observe() {
    return N;
  }
};

int observe();

int main() {
  SpookyAction<42>{};
  std::cout << observe() << '\n';  // Prints 42
}

Put the magic pieces together

那么結(jié)合上面所有的這些技巧,我們就可以得到下面的代碼:

namespace {
// This is a *different* type in every translation
// unit because of the anonymous namespace.
struct TranslationUnitTag {};
}
void hijack(Widget& w);
template <
  typename Tag,
  typename ForbiddenFun,
  ForbiddenFun forbidden_fun
> class HijackImpl {
  friend void hijack(Widget& w) {
    (w.*forbidden_fun)();
  }
};

// Every translation unit gets its own unique
// explicit instantiation because of the
// guaranteed-unique tag parameter.
template class HijackImpl<
  TranslationUnitTag,
  decltype(&Widget::forbidden),
  &Widget::forbidden
>;

完整代碼可以參見這里:@wandbox

總結(jié)一下:

我們通過顯式模板特化,將Widget::forbidden的函數(shù)指針傳遞給了HijackImpl示例,特化了模板函數(shù)hijack通過友員函數(shù)聲明,讓hijack函數(shù)可以在他處被調(diào)用,從而達(dá)成了小目標(biāo) 結(jié)語

寫這些,是希望你將上面的代碼用于實(shí)際產(chǎn)品代碼嗎?絕對(duì)不要這么做! 不要違背C++的封裝的原則,一旦打開潘多拉魔盒,那么你的產(chǎn)品代碼雖然看起來可運(yùn)行,但是將不可維護(hù),不可知,因?yàn)槟闫茐牧宋覀兒虲++語言以及程序員之間的合約。

到此這篇關(guān)于如何在C++類的外部調(diào)用類的私有方法的文章就介紹到這了,更多相關(guān)C++類外部調(diào)用類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言題目:有多少張桌子--并查集

    C語言題目:有多少張桌子--并查集

    并查集是一種用于管理分組的數(shù)據(jù)結(jié)構(gòu)。它具備兩個(gè)操作:(1)查詢?cè)豠和元素b是否為同一組 (2) 將元素a和b合并為同一組,需要的朋友可以參考下
    2021-09-09
  • opencv求解區(qū)域的內(nèi)接矩形

    opencv求解區(qū)域的內(nèi)接矩形

    這篇文章主要為大家詳細(xì)介紹了opencv求解區(qū)域的內(nèi)接矩形,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • C語言實(shí)現(xiàn)文件內(nèi)容按行隨機(jī)排列的算法示例

    C語言實(shí)現(xiàn)文件內(nèi)容按行隨機(jī)排列的算法示例

    這篇文章主要介紹了C語言實(shí)現(xiàn)文件內(nèi)容按行隨機(jī)排列的算法,涉及C語言字符串、數(shù)組遍歷與隨機(jī)數(shù)相關(guān)算法實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-09-09
  • C++面試八股文之了解auto關(guān)鍵字

    C++面試八股文之了解auto關(guān)鍵字

    這篇文章主要為大家介紹了C++面試八股文之了解auto關(guān)鍵字問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • C語言popen函數(shù)調(diào)用其他進(jìn)程返回值示例詳解

    C語言popen函數(shù)調(diào)用其他進(jìn)程返回值示例詳解

    這篇文章主要為大家介紹了C語言popen函數(shù)調(diào)用其他進(jìn)程返回值示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • C++日期類運(yùn)算符重載方式

    C++日期類運(yùn)算符重載方式

    這篇文章主要介紹了C++日期類運(yùn)算符重載方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C++模擬2D牛頓力學(xué)效果的示例代碼

    C++模擬2D牛頓力學(xué)效果的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C++模擬2D牛頓力學(xué)效果,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下
    2023-06-06
  • pthread_cond_wait() 用法深入分析

    pthread_cond_wait() 用法深入分析

    以下是對(duì)pthread_cond_wait的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-07-07
  • C語言經(jīng)典順序表真題演練講解

    C語言經(jīng)典順序表真題演練講解

    程序中經(jīng)常需要將一組數(shù)據(jù)元素作為整體管理和使用,需要?jiǎng)?chuàng)建這種元素組,用變量記錄它們,傳進(jìn)傳出函數(shù)等。一組數(shù)據(jù)中包含的元素個(gè)數(shù)可能發(fā)生變化,順序表則是將元素順序地存放在一塊連續(xù)的存儲(chǔ)區(qū)里,元素間的順序關(guān)系由它們的存儲(chǔ)順序自然表示
    2022-04-04
  • C++入門淺談之類和對(duì)象

    C++入門淺談之類和對(duì)象

    C++ 是一門面向?qū)ο蟮木幊陶Z言,理解 C++,首先要理解類(Class)和對(duì)象(Object)這兩個(gè)概念。下面和小編一起來學(xué)習(xí)吧
    2021-10-10

最新評(píng)論

岫岩| 成武县| 墨竹工卡县| 神池县| 内丘县| 海丰县| 宁强县| 南皮县| 江安县| 温泉县| 肥东县| 太康县| 绥滨县| 兴海县| 广西| 田东县| 长宁区| 鄄城县| 郁南县| 抚顺市| 淮安市| 万荣县| 河东区| 西乌珠穆沁旗| 通渭县| 静安区| 西丰县| 青河县| 黄龙县| 皋兰县| 滨州市| 平原县| 张北县| 阳高县| 泽普县| 曲麻莱县| 连南| 光山县| 依兰县| 广河县| 红河县|