亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++運(yùn)行時(shí)類型識(shí)別與轉(zhuǎn)換實(shí)現(xiàn)方法

 更新時(shí)間:2022年10月09日 08:43:20   作者:哎呀熊熊熊  
運(yùn)行時(shí)類型識(shí)別可能被認(rèn)為是C++中一個(gè)”次要“的特征,當(dāng)程序員在編程過程中陷入非常困難的境地時(shí),實(shí)用主義將會(huì)幫助他走出困境

當(dāng)僅有一個(gè)指針或引用指向基類型時(shí),利用運(yùn)行時(shí)類型識(shí)別(RTTI)可以找到一個(gè)對(duì)象的動(dòng)態(tài)類型。

運(yùn)行時(shí)類型識(shí)別可能被認(rèn)為是C++中一個(gè)”次要“的特征,當(dāng)程序員在編程過程中陷入非常困難的境地時(shí),實(shí)用主義將會(huì)幫助他走出困境。正常情況下,程序員需要有意忽略對(duì)象的準(zhǔn)確類型,而利用虛函數(shù)機(jī)制實(shí)現(xiàn)那個(gè)類型正確操作過程。然而,有時(shí)知道一個(gè)僅含一個(gè)基類指針的對(duì)象的準(zhǔn)確的運(yùn)行時(shí)類型(即多半是派生的類型)是非常有用的。有了此信息,就可以更有效地進(jìn)行某些特殊情況的操作,或者預(yù)防基類接口因無此信息而變得笨拙。

1.運(yùn)行時(shí)類型轉(zhuǎn)換

通過指針或者引用決定對(duì)象運(yùn)行時(shí)類型的一種方法是使用運(yùn)行時(shí)類型轉(zhuǎn)換(runtime cast),用這種方法可以查證所嘗試進(jìn)行的轉(zhuǎn)換正確與否。當(dāng)要把基類指針類型轉(zhuǎn)換為派生類時(shí),這個(gè)方法非常有用。由于繼承的層次結(jié)構(gòu)的典型描述說基類在派生類之上,所以這種類型轉(zhuǎn)換也成為向下類型轉(zhuǎn)換(downcast)。

請(qǐng)看下面的類層次結(jié)構(gòu):

在下面的程序代碼中,Investment類中有一個(gè)其他類沒有的額外操作,所以能夠運(yùn)行時(shí)知道Security指針是否引用了Investment對(duì)象是很重要的。為了實(shí)現(xiàn)檢查運(yùn)行時(shí)的類型轉(zhuǎn)換,每個(gè)類都持有一個(gè)整數(shù)標(biāo)識(shí)符,以便可以與層次結(jié)構(gòu)中其他的類區(qū)別開來。

#include <iostream>
#include <vector>
#include "../purge.h"
using namespace std;
class Security {
protected:
  enum { BASEID = 0 };
public:
  virtual ~Security() {}
  virtual bool isA(int id) { return (id == BASEID); }
};
class Stock : public Security {
  typedef Security Super;
protected:
  enum { OFFSET = 1, TYPEID = BASEID + OFFSET };
public:
  bool isA(int id) {
    return id == TYPEID || Super::isA(id);
  }
  static Stock* dynacast(Security* s) {
    return (s->isA(TYPEID)) ? static_cast<Stock*>(s) : 0;
  }
};
class Bond : public Security {
  typedef Security Super;
protected:
  enum { OFFSET = 2, TYPEID = BASEID + OFFSET };
public:
  bool isA(int id) {
    return id == TYPEID || Super::isA(id);
  }
  static Bond* dynacast(Security* s) {
    return (s->isA(TYPEID)) ? static_cast<Bond*>(s) : 0;
  }
};
class Investment : public Security {
  typedef Security Super;
protected:
  enum { OFFSET = 3, TYPEID = BASEID + OFFSET };
public:
  bool isA(int id) {
    return id == TYPEID || Super::isA(id);
  }
  static Investment* dynacast(Security* s) {
    return (s->isA(TYPEID)) ?
      static_cast<Investment*>(s) : 0;
  }
  void special() {
    cout << "special Investment function" << endl;
  }
};
class Metal : public Investment {
  typedef Investment Super;
protected:
  enum { OFFSET = 4, TYPEID = BASEID + OFFSET };
public:
  bool isA(int id) {
    return id == TYPEID || Super::isA(id);
  }
  static Metal* dynacast(Security* s) {
    return (s->isA(TYPEID)) ? static_cast<Metal*>(s) : 0;
  }
};
int main() {
  vector<Security*> portfolio;
  portfolio.push_back(new Metal);
  portfolio.push_back(new Investment);
  portfolio.push_back(new Bond);
  portfolio.push_back(new Stock);
  for(vector<Security*>::iterator it = portfolio.begin();
       it != portfolio.end(); ++it) {
    Investment* cm = Investment::dynacast(*it);
    if(cm)
      cm->special();
    else
      cout << "not an Investment" << endl;
  }
  cout << "cast from intermediate pointer:" << endl;
  Security* sp = new Metal;
  Investment* cp = Investment::dynacast(sp);
  if(cp) cout << "  it's an Investment" << endl;
  Metal* mp = Metal::dynacast(sp);
  if(mp) cout << "  it's a Metal too!" << endl;
  purge(portfolio);
} ///:~

多態(tài)的isA()函數(shù)檢查其參數(shù)是否與它的類型參數(shù)(id)相容,就意味著或者id與對(duì)象的typeID準(zhǔn)確地匹配,或者與對(duì)象的祖先之一的類型匹配(因?yàn)樵谶@種情況下調(diào)用Super::isA())。函數(shù)dynacast()在每個(gè)類中都是靜態(tài)的,dynacast()為其指針參數(shù)調(diào)用isA()來檢查類型轉(zhuǎn)換是否有效。

借助dynamic_cast操作符,C++提供這樣一個(gè)可檢查的類型轉(zhuǎn)換。使用dynamic_cast對(duì)前面的程序例子進(jìn)行重寫,就得到下面的程序:

//: C08:Security.h
#ifndef SECURITY_H
#define SECURITY_H
#include <iostream>
class Security {
public:
  virtual ~Security() {}
};
class Stock : public Security {};
class Bond : public Security {};
class Investment : public Security {
public:
  void special() {
    std::cout << "special Investment function" <<std::endl;
  }
};
class Metal : public Investment {};
#endif // SECURITY_H ///:~
// Uses RTTI's dynamic_cast.
#include <vector>
#include "../purge.h"
#include "Security.h"
using namespace std;
int main() {
  vector<Security*> portfolio;
  portfolio.push_back(new Metal);
  portfolio.push_back(new Investment);
  portfolio.push_back(new Bond);
  portfolio.push_back(new Stock);
  for(vector<Security*>::iterator it =
       portfolio.begin();
       it != portfolio.end(); ++it) {
    Investment* cm = dynamic_cast<Investment*>(*it);
    if(cm)
      cm->special();
    else
      cout << "not a Investment" << endl;
  }
  cout << "cast from intermediate pointer:" << endl;
  Security* sp = new Metal;
  Investment* cp = dynamic_cast<Investment*>(sp);
  if(cp) cout << "  it's an Investment" << endl;
  Metal* mp = dynamic_cast<Metal*>(sp);
  if(mp) cout << "  it's a Metal too!" << endl;
  purge(portfolio);
} ///:~

由于原來例子中大部分的代碼開銷用在了類型轉(zhuǎn)換檢查上,所以這個(gè)例子就變得如此之短。如果想要安全地進(jìn)行向下類型轉(zhuǎn)換,dynamic_cast要求使用的目標(biāo)類型是多態(tài)的(polymorphic)。這就要求該類必須至少有一個(gè)虛函數(shù)。幸運(yùn)的是,Security基類有一個(gè)虛析構(gòu)函數(shù),所以這里不需要再創(chuàng)建一個(gè)額外的函數(shù)去做這項(xiàng)工作。因?yàn)閐ynamic_cast在程序運(yùn)行時(shí)使用了虛函數(shù)表,所以比其他新式風(fēng)格的類型轉(zhuǎn)換操作來說它的代價(jià)更高。

用引用而非指針同樣也可以使用dynamic_cast,但是由于沒有諸如空引用這樣的情況,這就需要采用其他方法來了解類型轉(zhuǎn)換是否失敗。這個(gè)”其他方法“就是捕獲bad_cast異常,如下所示:

#include <typeinfo>
#include "Security.h"
using namespace std;
int main() {
  Metal m;
  Security& s = m;
  try {
    Investment& c = dynamic_cast<Investment&>(s);
    cout << "It's an Investment" << endl;
  } catch(bad_cast&) {
    cout << "s is not an Investment type" << endl;
  }
  try {
    Bond& b = dynamic_cast<Bond&>(s);
    cout << "It's a Bond" << endl;
  } catch(bad_cast&) {
    cout << "It's not a Bond type" << endl;
  }
} ///:~

2.typeid操作符

獲得有關(guān)一個(gè)對(duì)象運(yùn)行時(shí)信息的另一個(gè)方法,就是typeid操作符來完成。這種操作符返回一個(gè)type_info類的對(duì)象,該對(duì)象給出與其應(yīng)用有關(guān)的對(duì)象類型的信息。如果該對(duì)象的類型是多態(tài)的,它將給出那個(gè)應(yīng)用(動(dòng)態(tài)類型(dynamic type))的大部分派生類信息;否則,它將給出靜態(tài)類型信息。typeid操作符的一個(gè)用途是獲得一個(gè)對(duì)象的動(dòng)態(tài)類型的名稱,例如const char * ,就像在下面例子中可以看到的:

#include <iostream>
#include <typeinfo>
using namespace std;
struct PolyBase { virtual ~PolyBase() {} };
struct PolyDer : PolyBase { PolyDer() {} };
struct NonPolyBase {};
struct NonPolyDer : NonPolyBase { NonPolyDer(int) {} };
int main() {
  // Test polymorphic Types
  const PolyDer pd;
  const PolyBase* ppb = &pd;
  cout << typeid(ppb).name() << endl;
  cout << typeid(*ppb).name() << endl;
  cout << boolalpha << (typeid(*ppb) == typeid(pd))
       << endl;
  cout << (typeid(PolyDer) == typeid(const PolyDer))
       << endl;
  // Test non-polymorphic Types
  const NonPolyDer npd(1);
  const NonPolyBase* nppb = &npd;
  cout << typeid(nppb).name() << endl;
  cout << typeid(*nppb).name() << endl;
  cout << (typeid(*nppb) == typeid(npd)) << endl;
  // Test a built-in type
  int i;
  cout << typeid(i).name() << endl;
} ///:~

這是使用一個(gè)特定編譯器的程序的輸出是:

struct PolyBase const *
struct Polyder
true
true
struct NonPolyBase const *
struct NonPolyBase
false
int

因?yàn)閜pb是一個(gè)指針,所以輸出的第1行是他的靜態(tài)類型。為了在程序中得到RTTI的結(jié)果,需要檢查指針或引用目標(biāo)對(duì)象,這在第2行說明。需要注意的是,RTTI忽略了頂層的const和volatile限定符。借助非多態(tài)類型,正好可以獲得靜態(tài)類型(該指針本身的類型)。正如讀者所見,這里也支持內(nèi)置類型。

2.1類型轉(zhuǎn)換到中間層次類型

#include <cassert>
#include <typeinfo>
using namespace std;
class B1 {
public:
  virtual ~B1() {}
};
class B2 {
public:
  virtual ~B2() {}
};
class MI : public B1, public B2 {};
class Mi2 : public MI {};
int main() {
  B2* b2 = new Mi2;
  Mi2* mi2 = dynamic_cast<Mi2*>(b2);
  MI* mi = dynamic_cast<MI*>(b2);
  B1* b1 = dynamic_cast<B1*>(b2);
  assert(typeid(b2) != typeid(Mi2*));
  assert(typeid(b2) == typeid(B2*));
  delete b2;
} ///:~

如果創(chuàng)建一個(gè)Mi2對(duì)象并將它向上類型轉(zhuǎn)換到該繼承層次結(jié)構(gòu)的根(在這種情況下,選擇兩個(gè)可能的根中的一個(gè)),可以成功地使dynamic_cast回退至兩個(gè)派生層MI或Mi2中的任何一個(gè)。

甚至可以從一個(gè)根到另一個(gè)根進(jìn)行類型轉(zhuǎn)換:

B1* b1 = dynamic_cast<B1*>(b2);

這也是成功的,因?yàn)锽2實(shí)際上指向一個(gè)Mi2對(duì)象,該Mi2對(duì)象含有一個(gè)B1類型的子對(duì)象。

2.2void型指針

RTTI僅僅為完整的類型工作,這就意味著當(dāng)使用typeid時(shí),所有的類型信息必須是可利用的。特別是,它不能與void型指針一起工作:

//!#include <iostream>
#include <typeinfo>
using namespace std;
class Stimpy {
public:
  virtual void happy() {}
  virtual void joy() {}
  virtual ~Stimpy() {}
};
int main() {
  void* v = new Stimpy;
  // Error:
//!  Stimpy* s = dynamic_cast<Stimpy*>(v);
  // Error:
//!  cout << typeid(*v).name() << endl;
} ///:~

一個(gè)void* 真是的意思是”無類型信息“。

2.3運(yùn)用帶模板的RTTI

因?yàn)樗械念惸0逅龅墓ぷ骶褪钱a(chǎn)生類,所以類模板可以很好地與RTTI一起工作。RTTI提供了一條方便的途徑來獲得對(duì)象所在類的名稱。下面的示例打印出構(gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用順序:

#include <iostream>
#include <typeinfo>
using namespace std;
template<int id> class Announce {
public:
  Announce() {
    cout << typeid(*this).name() << " constructor" << endl;
  }
  ~Announce() {
    cout << typeid(*this).name() << " destructor" << endl;
  }
};
class X : public Announce<0> {
  Announce<1> m1;
  Announce<2> m2;
public:
  X() { cout << "X::X()" << endl; }
  ~X() { cout << "X::~X()" << endl; }
};
int main() { X x; } ///:~

在構(gòu)造函數(shù)內(nèi)和析構(gòu)函數(shù)內(nèi)部,RTTI信息產(chǎn)生打印的類名。類X利用繼承和組合兩個(gè)方式創(chuàng)建一個(gè)類。輸出如下:

Announce<0> constructor
Announce<1> constructor
Announce<2> constructor
X::X()
X::~X()
Announce<2> destructor
Announce<1> destructor
Announce<0> destructor

當(dāng)然,可能會(huì)得到不同的結(jié)果,這取決于編譯器如何表示它的name()信息。

3.多重繼承

RTTI機(jī)制必須正確地處理多重繼承的所有復(fù)雜性,包括虛基類virtual:

#include <iostream>
#include <typeinfo>
using namespace std;
class BB {
public:
  virtual void f() {}
  virtual ~BB() {}
};
class B1 : virtual public BB {};
class B2 : virtual public BB {};
class MI : public B1, public B2 {};
int main() {
  BB* bbp = new MI; // Upcast
  // Proper name detection:
  cout << typeid(*bbp).name() << endl;
  // Dynamic_cast works properly:
  MI* mip = dynamic_cast<MI*>(bbp);
  // Can't force old-style cast:
//! MI* mip2 = (MI*)bbp; // Compile error
} ///:~

typeid()操作符正確地檢測(cè)出實(shí)際對(duì)象的名字,即便它采用virtual基類指針完成這個(gè)任務(wù)的,dynamic_cast也正確地進(jìn)行工作。但實(shí)際上,編譯器不允許程序員用以前的方法嘗試強(qiáng)制進(jìn)行類型轉(zhuǎn)換:

MI* mip2 = (MI*)bbp; // Compile error

編譯器知道這樣做絕不是正確的方法,因此需要程序員使用dynamic_cast。

4.合理使用RTTI

垃圾再生器

為了進(jìn)一步地舉例說明RTTI的實(shí)際用途,下面的程序模擬了一個(gè)垃圾再生器。不同種類的”垃圾“被插入一個(gè)容器中,然后根據(jù)它們的動(dòng)態(tài)類型進(jìn)行分類。

// Describing trash.
#ifndef TRASH_H
#define TRASH_H
#include <iostream>
class Trash {
  float _weight;
public:
  Trash(float wt) : _weight(wt) {}
  virtual float value() const = 0;
  float weight() const { return _weight; }
  virtual ~Trash() {
    std::cout << "~Trash()" << std::endl;
  }
};
class Aluminum : public Trash {
  static float val;
public:
  Aluminum(float wt) : Trash(wt) {}
  float value() const { return val; }
  static void value(float newval) {
    val = newval;
  }
};
class Paper : public Trash {
  static float val;
public:
  Paper(float wt) : Trash(wt) {}
  float value() const { return val; }
  static void value(float newval) {
    val = newval;
  }
};
class Glass : public Trash {
  static float val;
public:
  Glass(float wt) : Trash(wt) {}
  float value() const { return val; }
  static void value(float newval) {
    val = newval;
  }
};
#endif // TRASH_H ///:~

用來表示垃圾類型單價(jià)的static值定義在實(shí)現(xiàn)文件中:

// A Trash Recycler.
#include "Trash.h"
float Aluminum::val = 1.67;
float Paper::val = 0.10;
float Glass::val = 0.23;
///:~

sunValue()模板從頭到尾對(duì)一個(gè)容器進(jìn)行迭代,顯示并計(jì)算結(jié)果:

//{L} Trash
// A Trash Recycler.
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <typeinfo>
#include <vector>
#include "Trash.h"
#include "../purge.h"
using namespace std;
// Sums up the value of the Trash in a bin:
template<class Container>
void sumValue(Container& bin, ostream& os) {
  typename Container::iterator tally = bin.begin();
  float val = 0;
  while(tally != bin.end()) {
    val += (*tally)->weight() * (*tally)->value();
    os << "weight of " << typeid(**tally).name()
       << " = " << (*tally)->weight() << endl;
    ++tally;
  }
  os << "Total value = " << val << endl;
}
int main() {
  srand(time(0)); // Seed the random number generator
  vector<Trash*> bin;
  // Fill up the Trash bin:
  for(int i = 0; i < 30; i++)
    switch(rand() % 3) {
      case 0 :
        bin.push_back(new Aluminum((rand() % 1000)/10.0));
        break;
      case 1 :
        bin.push_back(new Paper((rand() % 1000)/10.0));
        break;
      case 2 :
        bin.push_back(new Glass((rand() % 1000)/10.0));
        break;
    }
  // Note: bins hold exact type of object, not base type:
  vector<Glass*> glassBin;
  vector<Paper*> paperBin;
  vector<Aluminum*> alumBin;
  vector<Trash*>::iterator sorter = bin.begin();
  // Sort the Trash:
  while(sorter != bin.end()) {
    Aluminum* ap = dynamic_cast<Aluminum*>(*sorter);
    Paper* pp = dynamic_cast<Paper*>(*sorter);
    Glass* gp = dynamic_cast<Glass*>(*sorter);
    if(ap) alumBin.push_back(ap);
    else if(pp) paperBin.push_back(pp);
    else if(gp) glassBin.push_back(gp);
    ++sorter;
  }
  sumValue(alumBin, cout);
  sumValue(paperBin, cout);
  sumValue(glassBin, cout);
  sumValue(bin, cout);
  purge(bin);
} ///:~

因?yàn)槔徊患臃诸惖赝度氲揭粋€(gè)容器,這樣一來,垃圾的所有信息就”丟失“了。但是,為了稍后適當(dāng)?shù)貙?duì)廢料進(jìn)行分類,具體類型信息必須恢復(fù),這將用到RTTI。

可以通過使用map來改進(jìn)這種解決方案,該map將指向type_info對(duì)象的指針與一個(gè)包含Trash指針的vector關(guān)聯(lián)起來。因?yàn)橛诚裥枰粋€(gè)能識(shí)別排序的判定函數(shù),這里提供了一個(gè)名為TInfoLess的結(jié)構(gòu),它調(diào)用type_info::before()。注意,這里必須對(duì)sumValue()進(jìn)行不同的定義。

//{L} Trash
// Recyling with a map.
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <map>
#include <typeinfo>
#include <utility>
#include <vector>
#include "Trash.h"
#include "../purge.h"
using namespace std;
// Comparator for type_info pointers
struct TInfoLess {
  bool operator()(const type_info* t1, const type_info* t2)
  const { return t1->before(*t2); }
};
typedef map<const type_info*, vector<Trash*>, TInfoLess>
  TrashMap;
// Sums up the value of the Trash in a bin:
void sumValue(const TrashMap::value_type& p, ostream& os) {
  vector<Trash*>::const_iterator tally = p.second.begin();
  float val = 0;
  while(tally != p.second.end()) {
    val += (*tally)->weight() * (*tally)->value();
    os << "weight of "
       << p.first->name()  // type_info::name()
       << " = " << (*tally)->weight() << endl;
    ++tally;
  }
  os << "Total value = " << val << endl;
}
int main() {
  srand(time(0)); // Seed the random number generator
  TrashMap bin;
  // Fill up the Trash bin:
  for(int i = 0; i < 30; i++) {
    Trash* tp;
    switch(rand() % 3) {
      case 0 :
        tp = new Aluminum((rand() % 1000)/10.0);
        break;
      case 1 :
        tp = new Paper((rand() % 1000)/10.0);
        break;
      case 2 :
        tp = new Glass((rand() % 1000)/10.0);
        break;
    }
    bin[&typeid(*tp)].push_back(tp);
  }
  // Print sorted results
  for(TrashMap::iterator p = bin.begin();
      p != bin.end(); ++p) {
    sumValue(*p, cout);
    purge(p->second);
  }
} ///:~

為了直接調(diào)用type_info::name(),我們?cè)谶@里修改了sunValue(),因?yàn)樽鳛門rashMap::value_type對(duì)的第1個(gè)成員,type_info對(duì)象現(xiàn)在是可獲得的。這樣就避免了為了獲得正在處理的Trash的類型名而額外調(diào)用typeid,而這在該程序的以前版本中卻是必須做的。

5.RTTI的機(jī)制和開銷

實(shí)現(xiàn)RTTI典型的方法是,通過在類的虛函數(shù)表中放置一個(gè)附加的指針。這個(gè)指針指向那個(gè)特別類型的type_info結(jié)構(gòu)。typeid()表達(dá)式的結(jié)果非常簡(jiǎn)單:虛函數(shù)表指針取得type_info指針,并且產(chǎn)生一個(gè)對(duì)type_info結(jié)構(gòu)的引用。因?yàn)檫@正好是一個(gè)雙指針的解析操作,這是一個(gè)代價(jià)為常量時(shí)間的操作。

6.小結(jié)

盡管通常情況下會(huì)為一個(gè)指向其基類的指針進(jìn)行向上類型轉(zhuǎn)換,然后再使用那個(gè)基類的通用接口(通過虛函數(shù)),但是如果知道一個(gè)由基類指針指向的對(duì)象的動(dòng)態(tài)類型,有時(shí)候根據(jù)獲得的這些信息進(jìn)行相關(guān)處理可能會(huì)使事情變得更加有效,而這些正是RTTI所提供的。大部分通常的誤用來自一些程序員,這些誤用是由于他們不理解虛函數(shù)而實(shí)采用RTTI來做類型檢查的編碼所造成的。C++的基本原理似乎提供了對(duì)違反類型的定義規(guī)則和完整性的情況進(jìn)行監(jiān)督和糾正的強(qiáng)有力的工具和保護(hù),但是如果有誰想故意誤用或回避某一語言的特征,那么將沒有人可以組織他這樣做。

到此這篇關(guān)于C++運(yùn)行時(shí)類型識(shí)別與轉(zhuǎn)換實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)C++類型識(shí)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • OPENCV批量讀取圖片實(shí)現(xiàn)方法

    OPENCV批量讀取圖片實(shí)現(xiàn)方法

    下面小編就為大家?guī)硪黄狾PENCV批量讀取圖片實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的。現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • Qt實(shí)現(xiàn)解壓帶有密碼的加密文件

    Qt實(shí)現(xiàn)解壓帶有密碼的加密文件

    Quazip是Qt平臺(tái)下面的一個(gè)壓縮解壓縮庫。本文將利用Quazip實(shí)現(xiàn)解壓帶有密碼的加密文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-02-02
  • 基于Qt制作一個(gè)定時(shí)關(guān)機(jī)的小程序

    基于Qt制作一個(gè)定時(shí)關(guān)機(jī)的小程序

    這篇文章主要為大家詳細(xì)介紹了如何基于Qt制作一個(gè)有趣的定時(shí)關(guān)機(jī)的小程序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • 詳解c++11新特性之模板的改進(jìn)

    詳解c++11新特性之模板的改進(jìn)

    這篇文章主要介紹了詳解c++11新特性之模板的改進(jìn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 詳解Matlab繪制3D玫瑰花的方法(內(nèi)附旋轉(zhuǎn)版本)

    詳解Matlab繪制3D玫瑰花的方法(內(nèi)附旋轉(zhuǎn)版本)

    這篇文章主要為大家介紹了如何利用Matlab繪制3D版的玫瑰花以及旋轉(zhuǎn)版的3D玫瑰花,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手試一試
    2022-03-03
  • C語言樸素模式匹配算法實(shí)例代碼

    C語言樸素模式匹配算法實(shí)例代碼

    樸素模式匹配算法也稱為布魯特-福斯算法,感覺很是高大上,但是實(shí)現(xiàn)起來很簡(jiǎn)單。這篇文章主要給大家介紹了關(guān)于C語言樸素模式匹配算法的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • 淺談C++空間配置器allocator

    淺談C++空間配置器allocator

    在STL中,Memory Allocator處于最底層的位置,為一切的Container提供存儲(chǔ)服務(wù),是一切其他組件的基石。對(duì)于一般使用 STL 的用戶而言,Allocator是不可見的。本文將主要介紹C++空間配置器allocator
    2021-06-06
  • C++深入講解初始化列表的用法

    C++深入講解初始化列表的用法

    這篇文章主要介紹了C++成員初始化列表,除了可以使用構(gòu)造函數(shù)對(duì)類成員進(jìn)行初始化之外,C++還提供了另外一種初始化的方法,叫做成員初始化列表。下面來看看文章的詳細(xì)吧,需要的朋友可以參考一下
    2022-04-04
  • c++代碼實(shí)現(xiàn)tea加密算法的實(shí)例詳解

    c++代碼實(shí)現(xiàn)tea加密算法的實(shí)例詳解

    這篇文章主要介紹了c++代碼實(shí)現(xiàn)tea加密算法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • C++撲克牌的洗牌發(fā)牌游戲設(shè)計(jì)

    C++撲克牌的洗牌發(fā)牌游戲設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C++撲克牌的洗牌發(fā)牌游戲設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08

最新評(píng)論