顯示具有 [程式]C++ 標籤的文章。 顯示所有文章
顯示具有 [程式]C++ 標籤的文章。 顯示所有文章

2018年10月26日 星期五

插件成了 header only 的罩門

什麼是 header only? 可以先看此文了解一下 http://zevoid.blogspot.com/2012/04/c11-extern-template.html

簡單的說,header only 是把一個 class 的程式碼就包含在這個 class 中,而這個 class 就放在引入檔(.h)中供大家使用。有別於引入檔只放 class 介面,程式碼則放在 .cpp 中。

header only 的好處是執行快,因一大部份的函數可以用 inline 的方式呼叫,另外也不用再加 .cpp 或是還要連結程式庫(lib 或 dll)。

但有一個不得不面對的問題,class 的程式碼因不放在特定的 .cpp 中,那麼使用它的模組(exe、lib、dll)都得編譯出各別的執行碼,一般來說除了程式會比較胖之外,也沒有其它不好的影響。但是遇到插件就出問題了。

插件是一個 dll 檔,特點是要用的時候才載入,不用的時候可以卸載,但若某一個 class 產生的物件,其執行碼在那個被卸載的 dll 中,就會出大問題了,以下範例程式就是在演示這種情況。

2018年7月7日 星期六

快速排序法改良版

因遞廻會有爆掉堆疊的危險,所以若有可能盡可能用廻圈,但是不是可以用廻圈取決於關鍵變數,在一個廻圈後是不是須要保留其值,若不須要則可以重設其值,進行下一個廻圈的運行

以下用快速排序法做進一步的說明,先說它的改良法是青衫教的,我一直銘記在心

因快速排序法運行一個回合後會由定位點分割成左右兩部份,若要重設關鍵變數再處理左邊部份,右邊就失去關鍵變數沒法處理,反過來做亦相同,因此就讓較短的那邊用遞廻,長的那邊用廻圈

2018年5月8日 星期二

猜數字 - ML 多國語言應用範例

這是一個實驗程式,有兩個實驗目標。

  1. 測試 ML 在 主程式 和 插件 是否能各別建立自己的多國語言能力,但兩者間又能互通,因插件可能和主程式在不同時期或不同人所開發,因此能否各別獨立建立自己的多國語言能力,勢必成為必須的目標。但還得讓插件可以隨主程式一起變動,這是可選擇性的,但卻是最常用的選項。這部份的實驗很成功,同時使用 "wxWidgets 的延伸控制件 for ML" 可以即時更動 GUI 的文字語言,結果很令人滿意。
  2. 測試 主程式 和 插件 間的非同步互動,這部份花了最多時間,也很雜亂,應該還有 bug 存在,因有時還是會出槌。因為是非同步處理所以抓 bug 又很麻煩,所以點到就好了,主要還是在 ML 的實驗。事後想想若一開始用圖靈機制規劃好應該會比較容易。
主程式所用的譯文檔置於 Lang 子目錄下,插件所用的譯文檔在 plugin\GuestCore_1_0\Lang,插件還提供機器人用的 密語,純好玩別當真,可用 MLedit 增修更多語言的譯文檔。

2018年5月7日 星期一

MLedit 多國語言編輯器

這是為 ML 插件製作譯文檔的輔助程式,本身所用的譯文檔置於 Lang 子目錄下,觀迎大家幫忙擴增更多語言的譯文。

下載點:

完整檔案包,可直接執行 MLedit.exe

MLedit_0.1.0_complete.7z


精簡檔案包,適用於已安裝 CxxlMan2 開發環境懶人包,執行 "MLedit.exe - 捷徑 "

MLedit_0.1.0_simplify.7z


原始檔案包,適用於已安裝 CxxlMan2 開發環境懶人包,解壓到 C:\MySrc,支援 CMake 建立編譯專案

MLedit_0.1.0_Src.7z






CxxlMan2 開發環境懶人包

這是以 CodeBlocks 為開發環境架構出來的懶人包,包含 CxxlMan2 程式庫和插件、MinGw 5.1 以及  wxWidgets 3.1.1,內含設置說明

CxxlMan2 開發環境懶人包 20180606.7z


以下是 wxWidgets 教程簡體中文譯文:
https://wizardforcel.gitbooks.io/wxwidgets-book/index.html


2018年5月6日 星期日

wxWidgets 的延伸控制件 for ML(多國語言插件)

延伸 wxWidgets 的控制件,達成和 ML 互動
延伸出的控制件的命名為原控制件名稱後多加 Ext,如:wxMenuExt
配合 CodeBlocks 的 wxSmith 的用法以順利取代原控件

目前提供的控制件如以下所列,可依樣畫葫蘆自己增加

2018年4月5日 星期四

nPr 排列法

這方法會比旋轉要來得快

#include <functional>   // std::function
#include <memory>       // std::shared_ptr
#include <vector>
#include <iostream>

using namespace std;

// n 取 r 做排列
// 採用逆時旋轉排列法
// 必須 n >= r
class Permutation_nPr
{
  // 回報結果
  function<void(const shared_ptr<vector<unsigned char> > &, size_t)> 
    m_Report;
  // 放置要排列的數字
  shared_ptr <vector<unsigned char> > m_Digital_Array;
  // 要做排列的數目值
  size_t m_r;

  void v(size_t n, size_t r)
  {
    if (r == 0)
      m_Report(m_Digital_Array, m_r);
    else
      v(n - 1, r - 1);

    for (size_t j = n; j > 0; --j)
    {
      {
        unsigned char tmp = m_Digital_Array->at(n);
        m_Digital_Array->at(n) = m_Digital_Array->at(j-1);
        m_Digital_Array->at(j - 1) = tmp;
      }

      if (r == 0)
        m_Report(m_Digital_Array, m_r);
      else
        v(n - 1, r - 1);

      {
        unsigned char tmp = m_Digital_Array->at(n);
        m_Digital_Array->at(n) = m_Digital_Array->at(j-1);
        m_Digital_Array->at(j - 1) = tmp;
      }
    }
  }

public:
  Permutation_nPr(
   const function<void(const shared_ptr<vector<unsigned char> > &, size_t)>
      &Receive
  ):m_Report(Receive)
  {}

  void nPr(size_t n, size_t r)
  {
    m_r = r;
    m_Digital_Array =
       shared_ptr<vector<unsigned char> >(new vector<unsigned char>(n));
    size_t i = n;
    while (i--)
    {
      m_Digital_Array->at(i) = i;
    }
    v(n - 1, r - 1);
  }
};



class MsgShow
{
  int N{1};
public:
  void ResetN(){N = 1;}
  void operator()(
    const shared_ptr<vector<unsigned char> > &Digital_Array, size_t r)
  {
    cout << N << ":\t";
    for (size_t i = Digital_Array->size() - 1; r > 0; --i, --r)
      cout << (int)Digital_Array->at(i) << ' ';
    cout << endl;
    ++N;
  }
};

int main()
{
  MsgShow Report;
  Permutation_nPr P(Report);

  cout << '\n' << "4P3 排列:" << endl;
  Report.ResetN();
  P.nPr(4,3);

  return 0;
}



2018年3月15日 星期四

n 取 r 逆時鐘旋轉排列法

#include <functional>   // std::function
#include <memory>       // std::shared_ptr
#include <vector>
#include <iostream>
using namespace std;
// n 取 r 做排列 
// 採用逆時旋轉排列法
// 必須 n >= r
class Permutation_nPr
{
  // 回報結果
  function<void(const shared_ptr<vector<unsigned char> > &, size_t)> m_Report; 
  // 放置要排列的數字
  shared_ptr <vector<unsigned char> > m_Digital_Array;
  // 要做排列的數目值
  size_t m_r;
  void v(size_t n, size_t r)
  {
    size_t i = n + 1;
    while (i--)
    {
      if (r == 0)
        m_Report(m_Digital_Array, m_r);
      else
        v(n - 1, r - 1);
      unsigned char tmp = m_Digital_Array->at(n);
      for (size_t j = n; j > 0; --j)
        m_Digital_Array->at(j) = m_Digital_Array->at(j - 1);
      m_Digital_Array->at(0) = tmp;
    }
  }
public:
  Permutation_nPr(
     const function<void(const shared_ptr<vector<unsigned char> > &, size_t)> 
      &Receive
  )
     :m_Report(Receive)
  {}
  void nPr(size_t n, size_t r)
  {
    m_r = r;
    m_Digital_Array = 
       shared_ptr<vector<unsigned char> >(new vector<unsigned char>(n));
    size_t i = n;
    while (i--)
    {
      m_Digital_Array->at(i) = i;
    }
    v(n - 1, r - 1);
  }
};
int N = 1;
void Show(const shared_ptr<vector<unsigned char> > &Digital_Array, size_t r)
{
  cout << N << ":\t";
  for (size_t i = Digital_Array->size() - 1; r > 0; --i, --r)
    cout << (int)Digital_Array->at(i) << ' ';
  cout << endl;
  ++N;
}
int main()
{
  Permutation_nPr P(Show);
  cout << "4P3 排列:" << endl;
  N = 1;
  P.nPr(4, 3);
  return 0;
}

2018年3月14日 星期三

n 取 n 逆時鐘旋轉排列法


#include <functional>   // std::function
#include <memory>       // std::shared_ptr
#include <vector>
#include <iostream>
using namespace std;
// n 取 n 做排列 
// 採用逆時旋轉排列法
class Permutation_nPn
{
  // 回報結果
  function<void(const shared_ptr<vector<unsigned char> > &)> m_Report;
  // 放置要排的數字
  shared_ptr <vector<unsigned char> > m_Digital_Array;
  void v(size_t n)
  {
    if (n == 0)
      m_Report(m_Digital_Array);
    else
    {
      size_t i = n + 1;
      while (i--)
      {
        v(n - 1);
        unsigned char tmp = m_Digital_Array->at(n);
        for (size_t j = n; j > 0; --j)
          m_Digital_Array->at(j) = m_Digital_Array->at(j - 1);
        m_Digital_Array->at(0) = tmp;
      }
    }
  }
public:
  Permutation_nPn(
    const function<void(const shared_ptr<vector<unsigned char> > &)> 
    &Receive
  )
    :m_Report(Receive)
  {}
  void nPn(size_t n)
  {
    m_Digital_Array = shared_ptr<vector<unsigned char> >(
      new vector<unsigned char>(n));
    size_t i = n;
    while (i)
    {
      m_Digital_Array->at(i - 1) = i - 1;
      --i;
    }
    v(n - 1);
  }
};
int N = 1;
void Show(const shared_ptr<vector<unsigned char> > &Digital_Array)
{
  cout << N << ":\t";
  
  for (size_t i = Digital_Array->size(); i > 0; --i)
    cout << (int)Digital_Array->at(i - 1) << ' ';
  cout << endl;
  ++N;
}
int main()
{
  Permutation_nPn P(Show);  
  cout << "4! 排列:" << endl;
  N = 1;
  P.nPn(4);
  return 0;
}


2018年1月2日 星期二

Sprintf 簡單風格字串格式化

用於處理字串格式化的小工具,可指定參數在字串中的插入位置。

範例:

stringstream ss;
Sprintf(ss, "我搭{1}去{0}。", "台北", "火車");

{0} = 第一個參數
{1} = 第二個參數
...

若有錯誤回傳 false,表示指定的參數超過提供的數量範圍

下載:
SPRINTF_1_1_4.zip

2018年1月1日 星期一

TlcMultiple 小工具程式原碼

用於處理 CxxlMan2 函數庫 TLC 文件的同名項目的小工具。
最好的處理方式是 匯入->排序->匯出,以人工方式處理標示同名的項目。
除非確定自動刪除同名項目不會有問題,否則請小心使用 MultipleClear() 功能

下載:
TlcMultiple_1_0_0.zip

使用範例:
先安裝好 CxxlMan2 函數庫,以下是使用範例

2017年12月26日 星期二

靜態多型

相對於靜態多型就是一般較多使用的的動態多型,如:
class Base
{
public:
  virtual void f() = 0;
};
class Derived :public Base
{
  virtual void f() override
  {
  }
public:
};
若改為靜態多型可能會像以下這樣:
template<typename DERIVED>
class Base
{
public:
  void f()
  {
    static_cast<DERIVED*>(this)->f_Imp();
  }
};
class Derived :public Base<Derived>
{
  void f_Imp()
  {
  }
public:
  friend class Base<Derived>;
};

2017年12月25日 星期一

[分享]template 參數的 class 和 typename 還是有差別

若是要做 class 用,就明確指名 class 吧

// template<typename H> 這在 vs2015 過不了
template<class H>
class A
{
  void f()
  {
    cout << "OK" << endl;
  }
public:
  friend H;
};
class B
{
public:
  void f()
  {
    On_a.f();
  }
  A<B> On_a;
};

2017年12月23日 星期六

[轉貼]強制實作

此文截取自 http://www.programmer-club.com.tw/ShowSameTitleN/c/46861.html

用一個範例做個總結,也感謝 coco 提供的 assert,在 C++ 沒有提供 must 之下,還能做到類似的效果,
讓程式簡潔不少,也由此看出 must 的須要性

範例主要展示 prototype pattern 及 visitor pattern 的架構,不過 visitor pattern 做了改良,可以
採用 ClassID 做配對,可以在執行時期做較機動的處理,但為了減少篇幅和難度,還是寫死未做較機動的
處理

Class C 是為了表現未強制實作的後果,有幾處做了 remark,把 remark 的地方恢復,就可正常執行

2017年12月9日 星期六

CMRegSelf 插件註冊輔助

這是一個輔助性的插件,幫忙減輕 cxxlObjectPlugin 插件註冊的繁雜規劃,也減輕應用程式註冊插件的負擔。為此,CxxlMan2 的標準插件 CxxlMan2Plugin 全部修改成全面支援 CMRegSelf。

CMRegSelf 的機制在於讓 CxxlMan2Plugin 插件檔(dll 檔)有自我註冊插件的能力,並提供主程式註冊這些插件檔的功能。同時也提供一個範例,以期能完全瞭解這些運作。

注意!由於不同系列編譯器編碼的差異(比如 vc 與 gcc),不要把它們放置在一起或同一個插件搜尋路徑中,否則註冊處理時會有當掉的危險。所以內定的 CxxlMan2Plugin 資料夾也要有分別,比如分成 C:\CxxlMan2Plugin_vc 和 C:\CxxlMan2Plugin_gcc

下載點:
CMRegSelf_Src_20181106.zip

2017年10月12日 星期四

用 C++11 完美詮釋 Decorator pattern

Decorator UML class diagram.svg

By Trashtoy - My own work, written with text editor., Public Domain, Link

Decorator pattern 的類圖表明了所有處理、使用的對象都是 Component 介面,能夠操作的只有 Component 開放的功能,也就是 operation(),任何 Component 的實作類別都必須依自己的情況實作 operation()。其中有一個 Component 的延伸介面 Decorator,對 operation() 有一個明確的定義--除了做自己的事之外,還要呼叫的包裹對象的 operation()。

2017年10月3日 星期二

介面繼承 與 組合代替繼承

此文延伸自「虛擬函數多層強制實作」一文,若解說上有不明究理的地方可以先回頭看看。

在「虛擬函數多層強制實作」提到用 PROTOTYPE_BASE_CRTP 這個巨集來取代直接繼承的做法,可強制子孫類別都得強制實作某些虛擬函數,可是現在問題是如何強制必須使用這個巨集,所以只是把一個難題換成另一個難題而已。

所以還是得回歸 C++ 本身,C++ 只提供一層的強制實作,這應該有個光明正大的理由,文章最後有個看法也許可以成立。

PROTOTYPE_BASE_CRTP 巨集只是利用 C++ 的多重繼承在每個子孫類別再繼承一次純虛擬函數,以達到強制實作的目的,若這方式不可行,還有其它的方法嗎?

C++ 的純虛擬函數一次性實作,只要不實作就可以不斷的延續到子孫類別,所以只要採用「介面繼承」的方式就可以達到強制實作的目的。但類別資料繼承的部份要怎麼解決,不是程式設計界有句名言「組合代替繼承」,就用這兩招來試試。

2017年8月3日 星期四

虛擬函數多層強制實作

這裡留下 http://www.programmer-club.com.tw/ShowSameTitleN/c/46861.html 的討論結果。

C++ 的純虛擬函數只能強制實作一層,若希望多層的實作類別都必須實作,C++ 並沒有支援,以下示範如何建立多層強制實作的機制