欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++通用動(dòng)態(tài)抽象工廠的實(shí)現(xiàn)詳解

 更新時(shí)間:2022年07月12日 09:25:57   作者:用戶2471098440237  
在面向?qū)ο蟮木幊讨?一般通過繼承和虛函數(shù)來提供抽象能力,下面這篇文章主要給大家介紹了關(guān)于C++通用動(dòng)態(tài)抽象工廠的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

背景

一開始,我是想到了下面這個(gè)場景:

struct A {
  void Foo() {}
};

struct B {
  void Bar() {
    A().Foo();
  }
};

如上面代碼,B的Bar中構(gòu)造了A,然后調(diào)用了A的Foo函數(shù)。假如我想在別的場景中復(fù)用B的Bar,但是這時(shí)A的Foo就不符合需求了,需要定制,于是我們想到可以用多態(tài),把A的Foo改成虛函數(shù),然后寫出A1:

struct A {
  A() = default;
  virtual ~A() = default;
  virtual void Foo() {}
};

struct A1 : public A {
  void Foo() override {}
};

B不應(yīng)該知道A1的存在,為了讓B用上A1,同時(shí)也為以后可能會(huì)拓展的A2、A3做準(zhǔn)備,我們寫了個(gè)A的工廠函數(shù)GetA()來生成A。于是代碼變成:

std::unique_ptr<A> GetA() {
  if (Condition1()) {
    return std::unique_ptr<A>(new A1());
  } else {
    return std::unique_ptr<A>(new A());
  }
}

struct B {
  void Bar() {
    GetA()->Foo();
  }
};

如果B中還要構(gòu)造別的C、D等類,難道我們要為每個(gè)類都寫一個(gè)工廠函數(shù)嗎?這成本也太高了,而且可能大部分類都只有一個(gè),不用搞繼承,寫工廠函數(shù)就是無用功。那么,有沒有一種通用的方式可以在寫B(tài)代碼的時(shí)候就對(duì)A、C、D等類的構(gòu)造都留一手,使得以后可以由B外的代碼控制實(shí)際構(gòu)造的是A1等,而不需要修改B的代碼?這就是我寫動(dòng)態(tài)抽象工廠的原始需求。

實(shí)現(xiàn)

思路很簡單,就是為每個(gè)類都自動(dòng)生成一個(gè)工廠函數(shù)就好了,然后在B中不直接構(gòu)造A、C、D等對(duì)象,而是都調(diào)用對(duì)應(yīng)類的工廠函數(shù)。然后這個(gè)自動(dòng)生成的工廠默認(rèn)就是構(gòu)造原始的類的對(duì)象,比如A,也有接口可以改成生成子類,比如A1。對(duì)每個(gè)類生成一個(gè)工廠函數(shù)自然就想到用模板了。至于這個(gè)接口怎么實(shí)現(xiàn),就有兩大分支,分別是編譯期和運(yùn)行期。編譯期一般就是用模板特化了。我覺得運(yùn)行期會(huì)更有趣,用法會(huì)更多,就選了運(yùn)行期。

運(yùn)行期的意思就是要搞個(gè)變量來存下這個(gè)修改的工廠函數(shù),自然就想到用std::function。當(dāng)然免不了的是要把這個(gè)變量傳給B。如果管理A的是一個(gè)變量,管理C、D的是另外兩個(gè)變量,那就要傳很多很多變量給B,這樣也太繁瑣了,所以應(yīng)該一個(gè)變量存下所有類的工廠函數(shù),然后把這個(gè)變量傳遍所有需要使用工廠函數(shù)的對(duì)象或函數(shù)當(dāng)中。所以這個(gè)變量的類型是一個(gè)確定的類型,不能帶模板(或者說模板參數(shù)不能跟工廠對(duì)應(yīng)的類相關(guān),如A、C、D等)。那么模板就放到方法當(dāng)中了。很自然地,這個(gè)類型的接口就應(yīng)該是這樣:

struct DynamicAbstractFactory {
  template <typename T, typename... Args>
  std::unique_ptr<T> New(Args&&...);
};

這里插一段,為什么叫動(dòng)態(tài)抽象工廠呢?按照我的理解,工廠模式就是實(shí)現(xiàn)一個(gè)返回T*的函數(shù)F,里面用ifelse來控制最終返回的是T還是T的某個(gè)子類。抽象工廠模式就是連這個(gè)函數(shù)F都是可變的。動(dòng)態(tài)是指這個(gè)F是運(yùn)行時(shí)可變。

那么這個(gè)接口怎么實(shí)現(xiàn)呢?我的想法是用一個(gè)map來記錄類型組合(T, Args&&...)到工廠函數(shù)std::function<T*(Args&&...)>的映射,并存儲(chǔ)std::function<T*(Args&&...)>。New的實(shí)現(xiàn)就是查找map中有沒有對(duì)應(yīng)的工廠函數(shù),有就調(diào)用工廠函數(shù),沒有就調(diào)用T本身的構(gòu)造函數(shù)。當(dāng)然,也需要提供一個(gè)接口來修改這個(gè)map。

要實(shí)現(xiàn)這個(gè)map還有三個(gè)細(xì)節(jié):

  • 存儲(chǔ)的std::function<T*(Args&&...)>是不同的類型,需要用類型擦除存儲(chǔ)。如果可用C++17的話可直接用std::any,但我的環(huán)境有些老代碼用gcc7編不過,所以還是只能用C++11,于是用std::shared_ptr<void>來代替(我一開始還是用std::unique_ptr+虛析構(gòu)函數(shù)+繼承來實(shí)現(xiàn)的,后來才知道std::shared_ptr自帶這個(gè)功能)。
  • map的key是一個(gè)類型組合,就用std::type_index吧。由于std::function<T*(Args&&...)>已經(jīng)把整個(gè)類型組合包進(jìn)去了,而且一定會(huì)實(shí)例化,就直接用它吧。于是key就成了std::type_index(typeid(std::function<T*(Args&&...)>))。
  • 由于接口New(Args&&...)的每個(gè)參數(shù)類型Args&&都是引用類型,為了保持一致性,為了map能找到正確的函數(shù),要求std::function中的每個(gè)參數(shù)也是引用類型,所以上面都寫作std::function<T*(Args&&...)>。比如std::function<T*(int)>會(huì)轉(zhuǎn)換成std::function<T*(int&&)>。

再加上修改map的接口SetFunc,第一版的動(dòng)態(tài)抽象工廠就做好了:

class DynamicAbstractFactory {
 public:
  template <typename T, typename... Args>
  std::unique_ptr<T> New(Args&&... args) {
    auto iter = index2func_.find(std::type_index(typeid(std::function<T*(Args&&...)>)));
    if (iter != index2func_.end()) {
      return std::unique_ptr<T>((*reinterpret_cast<std::function<T*(Args&&...)>*>(iter->second.get()))(std::forward<Args>(args)...));
    }
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
  }

  template <typename T, typename... Args>
  void SetFunc(std::function<T*(Args...)>&& func) {
    index2func_[std::type_index(typeid(std::function<T*(Args&&...)>))] = std::make_shared<std::function<T*(Args&&...)>>(std::move(func));
  }

 protected:
  std::unordered_map<std::type_index, std::shared_ptr<void>> index2func_;
};

于是B的代碼及使用就變成這樣:

class B {
 public:
  B(DynamicAbstractFactory& factory) : factory_(factory) {}
  void Bar() {
    factory_.New<A>()->Foo();
    factory_.New<C>();
    factory_.New<D>();
  }
 protected:
  DynamicAbstractFactory& factory_;
};

// 舊環(huán)境,用原始A、C、D
// 當(dāng)然B也可以用factory來生成
void Run() {
  DynamicAbstractFactory factory;
  factory.New<B>(factory)->Bar();
}

// 新環(huán)境,用A1、C、D
void Run1() {
  DynamicAbstractFactory factory;
  std::function<A*()> get_a = []() {
    return new A1();
  };
  factory.SetFunc<A>(std::move(get_a));
  factory.New<B>(factory)->Bar();
}

這樣就滿足了一開始的需求,B在構(gòu)造A、C、D的時(shí)候都留了一手,B并不需要知道實(shí)際構(gòu)造的是什么,在B的外部,Run()和Run1(),可控制在B里具體要構(gòu)造的對(duì)象。

寫完后發(fā)現(xiàn)這東西作用不止于此,下面寫寫一些擴(kuò)展用法。

寄存參數(shù)

子類的構(gòu)造函數(shù)的參數(shù)可以跟父類不一樣,通過lambda捕獲來寄存。

struct A2 : public A {
  A2(int i) {}
  void Foo() override {}
};

void Run2() {
  DynamicAbstractFactory factory;
  int i = 0;
  std::function<A*()> get_a = [i]() {
    return new A2(i);
  };
  factory.SetFunc<A>(std::move(get_a));
  factory.New<B>(factory)->Bar();
}

存儲(chǔ)所有構(gòu)造出來的對(duì)象

上面的接口返回std::unique_ptr,還要管理對(duì)象生命周期,不如更進(jìn)一步,用factory來管理所有它構(gòu)造的對(duì)象,在factory析構(gòu)時(shí)統(tǒng)一析構(gòu)。因?yàn)槲乙话銓懞笈_(tái)rpc接口,可以在rpc請(qǐng)求開始時(shí)構(gòu)造factory,在構(gòu)造好回包后析構(gòu)factory,這樣在整個(gè)請(qǐng)求周期構(gòu)造的對(duì)象都在,指針不會(huì)失效,而且在請(qǐng)求結(jié)束后可以很方便地進(jìn)行異步析構(gòu),直接把factory丟到析構(gòu)線程就好。

于是New接口返回值由std::unique_ptr改成T*,同時(shí)New可能會(huì)造成誤解,改成Get。當(dāng)然,存儲(chǔ)肯定要用到類型擦除存儲(chǔ)。就成了下面這樣:

class GeneralStorage {
 public:
  GeneralStorage(size_t reserve_size = 256) {
    storage_.reserve(reserve_size);
  }
  ~GeneralStorage() {
    // 保證按添加順序逆序析構(gòu)
    while (storage_.size() > 0) {
      storage_.pop_back();
    }
  }

  template <class T, class... Args>
  T* EmplaceBack(Args&&... args) {
    auto p_obj = std::make_shared<T>(std::forward<Args>(args)...);
    storage_.push_back(p_obj);
    return p_obj.get();
  }

 protected:
  std::vector<std::shared_ptr<void>> storage_;
};

class DynamicAbstractFactoryWithStorage {
 public:
  template <typename T, typename... Args>
  T* Get(Args&&... args) {
    auto iter = index2func_.find(std::type_index(typeid(std::function<T*(Args&&...)>)));
    if (iter != index2func_.end()) {
      return (*reinterpret_cast<std::function<T*(Args&&...)>*>(iter->second.get()))(std::forward<Args>(args)...);
    }
    return storage_.EmplaceBack<T>(std::forward<Args>(args)...));
  }

  template <typename T, typename... Args>
  void SetFunc(std::function<T*(Args...)>&& func) {
    index2func_[std::type_index(typeid(std::function<T*(Args&&...)>))] = std::make_shared<std::function<T*(Args&&...)>>(std::move(func));
  }

 protected:
  std::unordered_map<std::type_index, std::shared_ptr<void>> index2func_;
  GeneralStorage storage_; 
};

有個(gè)細(xì)節(jié)是對(duì)于改變過的工廠函數(shù)返回的指針是不應(yīng)該存在storage_中的,而應(yīng)該是在工廠函數(shù)中把對(duì)象存進(jìn)storage_。上面的Run1()應(yīng)該改成這樣:

void Run1() {
  DynamicAbstractFactoryWithStorage factory;
  std::function<A*()> get_a = [&factory]() {
    return factory.Get<A1>();
  };
  factory.SetFunc<A>(std::move(get_a));
  factory.Get<B>(factory)->Bar();
}

寄存指針,可析構(gòu)的單例

當(dāng)返回值由std::unique_ptr改成T*,就可以實(shí)現(xiàn)寄存指針了。可析構(gòu)的單例指每次請(qǐng)求都重新構(gòu)造,在請(qǐng)求結(jié)束后析構(gòu),但是請(qǐng)求之中只構(gòu)造一次??聪旅胬樱?/p>

struct C {
  C(DynamicAbstractFactoryWithStorage& factory) {
    std::function<C*(DynamicAbstractFactoryWithStorage&)> func = [this](DynamicAbstractFactoryWithStorage& factory) {
      return this;
    };
    factory.SetFunc<C>(std::move(func));
  }
};

void Run() {
  DynamicAbstractFactoryWithStorage factory;
  factory.Get<C>(factory); // 構(gòu)造C,并通過SetFunc把對(duì)象的指針寄存到factory中
  factory.Get<C>(factory); // 調(diào)用C構(gòu)造函數(shù)中的func,直接返回寄存的指針,不重復(fù)構(gòu)造C
  // factory析構(gòu)時(shí)C的對(duì)象將被析構(gòu)
}

裝飾工廠函數(shù),責(zé)任鏈工廠

只要再加個(gè)接口GetFunc來獲取當(dāng)前的工廠函數(shù),就可以對(duì)工廠函數(shù)玩裝飾模式了。

GetFunc接口:

// 其它代碼與上面一樣
class DynamicAbstractFactoryWithStorage {
 public:
  template <typename T, typename... Args>
  std::function<T*(Args&&...)> GetFunc() {
    auto iter = index2func_.find(std::type_index(typeid(std::function<T*(Args&&...)>)));
    if (iter != index2func_.end()) {
      return *reinterpret_cast<std::function<T*(Args&&...)>*>(iter->second.get());
    }
    std::function<T*(Args&&...)> default_func = [this](Args&&... args) {
      return storage_.EmplaceBack<T>(std::forward<Args>(args)...));
    };
    return default_func;
  }
};

統(tǒng)計(jì)調(diào)用次數(shù):

struct C {
  C(DynamicAbstractFactoryWithStorage& factory) {
    std::function<C*(DynamicAbstractFactoryWithStorage&)> func = [this](DynamicAbstractFactoryWithStorage& factory) {
      return this;
    };
    factory.SetFunc<C>(std::move(func));
  }

  uint32_t cnt_ = 0;
};

void Run() {
  DynamicAbstractFactoryWithStorage factory;
  auto func = factory.GetFunc<A>();
  std::function<A*()> get_a = [func, &factory]() {
    ++factory.Get<C>()->cnt_;
    return func();
  };
  factory.SetFunc<A>(std::move(get_a));
  factory.Get<B>(factory)->Bar();
}

用責(zé)任鏈模式搞個(gè)工廠:

struct D {
  D() {}
  D(int i) {}
};

struct D1 : public D {
  D1(int i) {}

  static void SetFactoryD(DynamicAbstractFactoryWithStorage& factory) {
    // GetFunc的結(jié)果是std::fuction<D*(int&&)>類型的,這里經(jīng)過了一次類型轉(zhuǎn)換
    std::function<D*(int)> func = factory.GetFunc<D, int>();
    std::function<D*(int)> new_func = [func, &factory](int i) -> D* {
      // 責(zé)任鏈模式
      if (Check(i)) {
        return factory.Get<D1>(i);
      } else {
        return func(i);
      }
    };
    factory.SetFunc<D>(std::move(new_func));
  }

  // 構(gòu)造D1的條件
  static bool Check(int i) {
    return i == 1;
  }
};

// 與D1類似,除了Check
struct D2 : public D {
  D2(int i) {}

  static void SetFactoryD(DynamicAbstractFactoryWithStorage& factory) {
    std::function<D*(int)> func = factory.GetFunc<D, int>();
    std::function<D*(int)> new_func = [func, &factory](int i) -> D* {
      if (Check(i)) {
        return factory.Get<D2>(i);
      } else {
        return func(i);
      }
    };
    factory.SetFunc<D>(std::move(new_func));
  }

  // 構(gòu)造D2的條件
  static bool Check(int i) {
    return i == 2;
  }
};

void Run() {
  DynamicAbstractFactoryWithStorage factory;
  D1::SetFactoryD(factory);
  D2::SetFactoryD(factory);
  factory.Get<D>(0); // D
  factory.Get<D>(1); // D1
  factory.Get<D>(2); // D2
}

允許構(gòu)造函數(shù)之外的參數(shù)組合

上面的實(shí)現(xiàn)要求new T(std::forward(args)...)能合法生成一個(gè)T對(duì)象指針,在一些情況下很難做到,比如T中有難以初始化的成員,又比如T是一個(gè)抽象類:

struct E {
  E() = default;
  virtual ~E() = default;
  virtual void Foo() = 0;
};

這樣就要修改Get接口的邏輯,改成如果能合法調(diào)用構(gòu)造函數(shù),就調(diào)用,否則就不調(diào)用。但是這樣放開之后,就各種參數(shù)組合都可以搞了,我覺得這樣可能會(huì)很混亂,這邊設(shè)置了這個(gè)參數(shù)組合,那邊設(shè)置了另外的參數(shù)組合,不知道一共設(shè)置了哪幾種參數(shù)組合。我覺得還是要加點(diǎn)限制,就規(guī)定參數(shù)組合必須在基類中定義。規(guī)定了一個(gè)方法名FactoryGet,所有非構(gòu)造函數(shù)的參數(shù)組合要定義一個(gè)靜態(tài)FactoryGet方法,方法返回T*,比如:

struct E {
  E() = default;
  static E* FactoryGet(int) {
    return nullptr;
  }
  virtual ~E() = default;
  virtual void Foo() = 0;
};

這樣Get接口的邏輯就可以改成如果能合法調(diào)用構(gòu)造函數(shù),就調(diào)用,否則就調(diào)用對(duì)應(yīng)的FactoryGet方法,其他參數(shù)組合將會(huì)編譯報(bào)錯(cuò)。同時(shí)也規(guī)定FactoryGet獲得的指針不存進(jìn)通用存儲(chǔ)。于是DynamicAbstractFactoryWithStorage就改成這樣:

// new T(std::forward<Args>(args)...)
// T::FactoryGet(std::forward<Args>(args)...)
// 要求上面兩個(gè)表達(dá)式有且僅有一個(gè)合法并且返回T*,Get調(diào)用合法的那個(gè)。
template <typename T, typename F, typename = void>
struct DefaultGet;

template <typename T, typename... Args>
struct DefaultGet<T, void(Args...), typename std::enable_if<std::is_same<decltype(std::decay<T>::type::FactoryGet(std::forward<Args>(*reinterpret_cast<typename std::decay<Args>::type*>(0))...)), T*>::value, void>::type> {
  static T* Get(GeneralStorage& storage, Args&&... args) {
    return T::FactoryGet(std::forward<Args>(args)...);
  }
};

template <typename T, typename... Args>
struct DefaultGet<T, void(Args...), typename std::enable_if<std::is_same<decltype(new typename std::decay<T>::type(std::forward<Args>(*reinterpret_cast<typename std::decay<Args>::type*>(0))...)), typename std::decay<T>::type*>::value, void>::type> {
  static T* Get(GeneralStorage& storage, Args&&... args) {
    return storage.EmplaceBack<typename std::decay<T>::type>(std::forward<Args>(args)...);
  }
};

class DynamicAbstractFactoryWithStorage {
 public:
  // 每個(gè)Args都要是引用
  template <typename T, typename... Args>
  using FuncType = std::function<T*(Args&&...)>;

  template <typename T, typename... Args>
  T* Get(Args&&... args) {
    auto iter = index2func_.find(std::type_index(typeid(FuncType<T, Args...>)));
    if (iter != index2func_.end()) {
      return (*reinterpret_cast<FuncType<T, Args...>*>(iter->second.get()))(std::forward<Args>(args)...);
    }
    return DefaultGet<T, void(Args&&...)>::Get(storage_, std::forward<Args>(args)...);
  }

  template <typename T, typename... Args>
  void SetFunc(std::function<T*(Args...)>&& func) {
    index2func_[std::type_index(typeid(FuncType<T, Args...>))] = std::make_shared<FuncType<T, Args...>>(std::move(func));
  }

  template <typename T, typename... Args>
  FuncType<T, Args...> GetFunc() {
    auto iter = index2func_.find(std::type_index(typeid(FuncType<T, Args...>)));
    if (iter != index2func_.end()) {
      return *reinterpret_cast<FuncType<T, Args...>*>(iter->second.get());
    }
    FuncType<T, Args...> default_func = [this](Args&&... args) {
      return DefaultGet<T, void(Args&&...)>::Get(storage_, std::forward<Args>(args)...);
    };
    return default_func;
  }

 protected:
  std::unordered_map<std::type_index, std::shared_ptr<void>> index2func_;
  GeneralStorage storage_;
};

這樣E就能像上面那樣用了。另外,想要返回const指針也是可以的。

struct E {
  E() = default;
  // 返回值改成了const E*
  static const E* FactoryGet(int) {
    return nullptr;
  }
  virtual ~E() = default;
  virtual void Foo() = 0;
};

struct E1 : public E {
  E1(int i) {}
  static void SetFactoryE(DynamicAbstractFactoryWithStorage& factory) {
    std::function<const E*(int)> func = factory.GetFunc<const E, int>();
    std::function<const E*(int)> new_func = [func, &factory](int i) -> const E* {
      if (Check(i)) {
        return factory.Get<const E1>(i);
      } else {
        return func(i);
      }
    };
    factory.SetFunc<const E>(std::move(new_func));
  }
  static bool Check(int i) {
    return i == 1;
  }

  void Foo() override {}
};

void Run() {
  DynamicAbstractFactoryWithStorage factory;
  E1::SetFactoryE(factory);
  factory.Get<const E>(0); // nullptr
  factory.Get<const E>(1); // const E1*
}

總結(jié)

到此這篇關(guān)于C++通用動(dòng)態(tài)抽象工廠的文章就介紹到這了,更多相關(guān)C++通用動(dòng)態(tài)抽象工廠內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談C語言中的sizeof()和strlen()的區(qū)別

    淺談C語言中的sizeof()和strlen()的區(qū)別

    本文主要介紹了C語言中的sizeof()和strlen()的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C++11/14 線程的創(chuàng)建與分離的實(shí)現(xiàn)

    C++11/14 線程的創(chuàng)建與分離的實(shí)現(xiàn)

    這篇文章主要介紹了C++11/14 線程的創(chuàng)建與分離的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • C/C++項(xiàng)目編譯工具簡單介紹

    C/C++項(xiàng)目編譯工具簡單介紹

    我們給大家?guī)砹艘黄P(guān)于C/C++項(xiàng)目編譯工具簡單介紹的文章,大家在項(xiàng)目編譯前可以先閱讀下。
    2019-12-12
  • C語言實(shí)現(xiàn)簡單電子通訊錄

    C語言實(shí)現(xiàn)簡單電子通訊錄

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡單電子通訊錄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • C語言基于回溯算法解決八皇后問題的方法

    C語言基于回溯算法解決八皇后問題的方法

    這篇文章主要介紹了C語言基于回溯算法解決八皇后問題的方法,簡單描述了八皇后問題,并結(jié)合實(shí)例形式分析了C語言使用回溯算法解決八皇后問題的相關(guān)操作技巧,需要的朋友可以參考下
    2018-06-06
  • C++實(shí)現(xiàn)圖書館案例

    C++實(shí)現(xiàn)圖書館案例

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)圖書館案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C++全面覆蓋內(nèi)存管理知識(shí)講解

    C++全面覆蓋內(nèi)存管理知識(shí)講解

    本章主要介紹C語言與C++的內(nèi)存管理,以C++的內(nèi)存分布作為引入,介紹C++不同于C語言的內(nèi)存管理方式(new delete對(duì)比 malloc free),感興趣的朋友來看看吧
    2022-06-06
  • C語言中g(shù)etchar和putchar的使用方法詳解

    C語言中g(shù)etchar和putchar的使用方法詳解

    我們知道scanf函數(shù)可以從鍵盤輸入信息,而printf則可以輸出信息,同樣地,getchar和putchar也有同樣的功能,下面我來給大家介紹putchar和getchar的使用方法,需要的朋友可以參考下
    2023-08-08
  • 使用OpenCV實(shí)現(xiàn)檢測和追蹤車輛

    使用OpenCV實(shí)現(xiàn)檢測和追蹤車輛

    這篇文章主要為大家詳細(xì)介紹了使用OpenCV實(shí)現(xiàn)檢測和追蹤車輛,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C語言結(jié)構(gòu)體成員賦值的深拷貝與淺拷貝詳解

    C語言結(jié)構(gòu)體成員賦值的深拷貝與淺拷貝詳解

    C語言中的淺拷貝是指在拷貝過程中,對(duì)于指針型成員變量只拷貝指針本身,而不拷貝指針?biāo)赶虻哪繕?biāo),它按字節(jié)復(fù)制的。深拷貝除了拷貝其成員本身的值之外,還拷貝成員指向的動(dòng)態(tài)內(nèi)存區(qū)域內(nèi)容。本文將通過示例和大家詳細(xì)說說C語言的深拷貝與淺拷貝,希望對(duì)你有所幫助
    2022-09-09

最新評(píng)論