Pages

2010年12月31日 星期五

C++多重繼承

下面為C++多重繼承的網路經典範例。

//程序作者:管寧
//站點:www.cndev-lab.com
//所有稿件均有版權,如要轉載,請務必著名出處和作者

#include <iostream>
using namespace std;

class Vehicle {
public:
    Vehicle(int weight = 0) {
        Vehicle::weight = weight;
        cout << "載入Vehicle類構造函數" << endl;
    }
    void SetWeight(int weight) {
        cout << "重新設置重量" << endl;
 Vehicle::weight = weight;
    }
    virtual void ShowMe() = 0;
protected:
    int weight;
};

class Car: virtual public Vehicle//汽車,這裡是虛擬繼承
{
public:
    Car(int weight = 0, int aird = 0) : Vehicle(weight) {
        Car::aird = aird;
        cout << "載入Car類構造函數" << endl;
    }
    void ShowMe() {
        cout << "我是汽車!" << endl;
    }
protected:
    int aird;
};

class Boat: virtual public Vehicle//船,這裡是虛擬繼承
{
public:
    Boat(int weight = 0, float tonnage = 0) : Vehicle(weight) {
        Boat::tonnage = tonnage;
        cout << "載入Boat類構造函數" << endl;
    }
    void ShowMe() {
        cout << "我是船!" << endl;
    }
protected:
    float tonnage;
};



class AmphibianCar: public Car, public Boat//水陸兩用汽車,多重繼承的體現
{
public:
    AmphibianCar(int weight, int aird, float tonnage) : Vehicle(weight), Car(weight, aird), Boat(weight, tonnage)
    //多重繼承要注意調用基類構造函數
    {
        cout << "載入AmphibianCar類構造函數" << endl;
    }
    void ShowMe() {
        cout << "我是水陸兩用汽車!" << endl;
    }
    void ShowMembers() {
     cout << " 重量:" << weight << "頓," << "空氣排量:" << aird << "CC," << "排水量:" << tonnage << " 頓" << endl;
    }
};
int main() {
    AmphibianCar a(4, 200, 1.35f);
    a.ShowMe();
    a.ShowMembers();
    a.SetWeight(3);
    a.ShowMembers();
    system("pause");
    return 0;
}


載入Vehicle類構造函數
載入Car類構造函數
載入Boat類構造函數
載入AmphibianCar類構造函數
我是水陸兩用汽車!
 重量:4頓,空氣排量:200CC,排水量:1.35 頓
重新設置重量
 重量:3頓,空氣排量:200CC,排水量:1.35 頓
請按任意鍵繼續 . . . 
但是C++多重繼承有個問題是當繼承的方法或變數有相同的時候,到底要用哪種呢?

是否有方法可以直接指定要用哪個繼承的方法?

#include <iostream>
using namespace std;
class AA {
public:
    AA() {
    }
    void fat() {      
 printf("Addidas is Fat\n");
    }
};

class BB {
public:
    BB() {
    }
    void fat() {
 printf("Bill is Fat\n");
    }
};



class CC: public AA, public BB {
public:
    using AA::fat;
    CC() {

    }
};

class DD: public AA, public BB {
public:
    DD() {
    }
};

int main() {
    CC ca;
    printf("C is call..: ");
    ca.fat();
    DD da;
    printf("D is call..: \n");
    da.AA::fat();
    da.BB::fat();
    return 0;
}


C is call..: Addidas is Fat
D is call..: 
Addidas is Fat
Bill is Fat

由此可知,AA::fat() using AA::fat 皆可指定繼承的哪個方法會被使用。

Apache Tomcat Native library which allows optimal performance

利用用Eclipse 和tomcat 6.0,運行tomcat時候出現如下問題:
tomcat6.0
The Apache Tomcat Native library which allows optimal performance in
production environments was not found on the java.library.path

這是一個跟ARP有關的問題

APR(Apache
portable Run-time libraries,Apache可移植運行庫)
,
主要為上層的應用程序提供一個可以跨越多操作系統平台使用的底層支持接口庫。在早期Apache版本中,應用程序本身必須能夠處理各種具體操作系統平台的細節,並針對不同的平台調用不同的處理函數。隨著Apache的進一步開發,Apache組織決定將這些通用的函數獨立出來並發展成為一個新的項目。這樣,APR的開發就從Apache中獨立出來,Apache僅僅是使用APR而已。目前APR主要還是由Apache使用,不過由於APR的較好的移植性,因此一些需要進行移植的C程序也開始使用APR,開源項目比如Flood loadertester(http://httpd.apache.org/test /flood/,該項目用於服務器壓力測試,不僅僅適用於Apache)、FreeSwitch(www.freeswitch.org),JXTA-C(http://jxta-c.jxta.org,C版本的JXTA點對點平台實現);商業的項目則包括Blogline(http://www.bloglines.com/,covalent(http:
//www.covalent.net)等等。APR使得平台細節的處理進行下移。對於應用程序而言,它們根本就不需要考慮具體的平台,不管是Unix、Linux還是Window,應用程序執行的接口基本都是統一一致的。因此對於APR而言,可移植性和統一的上層接口是其考慮的一個重點。而APR最早的目的並不是如此,它最早只是希望將Apache中用到的所有代碼合併為一個通用的代碼庫,然而這不是一個正確的策略,因此後來APR改變了其目標。有的時候使用公共代碼並不是一件好事,比如如何將一個請求映射到線程或者進程是平台相關的,因此僅僅一個公共的代碼庫並不能完成這種區分。
APR的目標則是希望安全合併所有的能夠合併的代碼而不需要犧牲性能。APR的最早的一個目標就是為所有的平台(不是部分)提供一個公共的統一操作函數接口,這是一個非常了不起的目的,當然也是不現實的一個目標。我們不可能支持所有平台的所有特徵,因此APR目前只能為大多數平台提供所有的APR特性支持,包括Win32、OS/2、BeOS、Darwin、Linux等等。為了能夠實現這個目標,APR開發者必須為那些不能運行於所有平台的特性創建了一系列的特徵宏(FEATUREMACROS)以在各個平台之間區分這些特徵。


[解決辦法]
1. 到 [http://www.apache.org/dist/tomcat/tomcat-connectors/native/] 下載 [tcnative-1.dll]
2. 放到 [\TOMCAT_HOME\bin\] 下,重起eclipse 。

note: 放在 [windows\system32\下],應該也是可以。

2010年12月30日 星期四

【CMD】大量刪除指令

Windows下,[cmd]大量刪除指令  [delDir.bat]


@echo 移動到該磁區
c:
@echo 刪除資料夾下所有檔案(包含該資料夾本身)
rmdir C:\temp\source\ /s/y
@echo 建立資料夾
md C:\temp\source\

rmdir 指令參數 [rmdir [folder] /s /q
/s : 刪除指定目錄和所有子目錄,包括任何文件。.
/q : 刪除目錄無確認。
/? : 顯示幫助在命令提示。

【CMD】大量複製指令

Windows下,大量複製指令   [movefile.bat]

@echo 移動到該磁區
c:
@echo 移動磁碟中一個檔案
copy C:\temp\source\test.java C:\project\source\
@echo 移動磁碟中資料夾內所有檔案包含樹狀結構(子資料夾下的檔案)
xcopy C:\temp\source\ C:\project\source\ /s/y
@echo 暫停指令
pause

/S 複製每個目錄及其包含的子目錄。
/D 複製發生變更的檔案。
/Y 所有覆蓋的詢問都回答 YES

完整的
參數內容(從xcopy /?得知):

XCOPY source [destination] [/A | /M] [/D[:date]] [/P] [/S [/E]] [/V] [/W] [/C] [/I] [/Q] [/F] [/L] [/G] [/H] [/R] [/T] [/U] [/K] [/N] [/O] [/X] [/Y] [/-Y] [/Z]\r\r [/EXCLUDE:file1[+file2][+file3]...]

source 指定要複製的檔案。
destination 指定位置或者/以及新檔案的名稱。


/A 只複製設定成保存屬性的檔案,不要改變屬性的設定。
/M 只複製設定成保存屬性的檔案,並清除保存屬性。
/D:m-d-y 複製在指定日期當天或之後發生變更的檔案。如果沒有給日期,
只複製那些來源檔案日期比目的檔案日期為新的檔案。
/EXCLUDE:file1[+file2][+file3]...
指定檔案清單字串。每個字串
應該在檔案中的不同行。如果有字串對應到要進行複製的檔案絕

對路徑的任何部分,這個檔案會被排除複製。例如,指定字串\obj\ 或 .obj 的話,會排除所有在 obj 目錄下副檔名是.obj 的檔案複製。
/P 在建立每個目的檔案時顯示提示。
/S 複製每個目錄及其包含的子目錄,不複製空目錄。
/E 複製每個目錄及其包含的子目錄,也複製空目錄。/S 與 /E相同,能夠用來修改 /T。
/V 驗證每個新檔案。
/W 在複製之前提示您按鍵繼續。
/C 如果錯誤發生時也繼續複製。
/I 如果目的不存在且複製一個以上的檔案的話,就假設指定的目的一定是目錄。
/Q 在複製時不要顯示檔名。
/F 在複製時顯示來源及目的檔案的全部檔名。
/L 顯示要複製的檔案。
/G 允許加密檔案複製到不支援加密的目的地。
/H 時複製隱藏檔和系統檔。
/R 覆蓋唯讀檔案。
/T 建立目錄結構,但不複製其中的檔案。不包括空目錄及子目錄。
/T /E 會包括空目錄及子目錄。
/U 只複製已經存在目的位置的檔案。
/K 複製檔案屬性。通常 Xcopy 會重設唯讀的屬性。
/N 用所產生的短檔名來進行複製。
/O 複製檔案所有權及 ACL 資訊。
/X 複製檔案審查設定 (包含 /O)。
/Y 不要提示您確認是否要覆蓋一個已經存在的檔案。
/-Y 示您確認是否要覆蓋一個已經存在的檔案。
/Z 在可重新開始的模式中複製網路檔案。

參數 /Y 可以在 COPYCMD 環境變數中預先設定。但可以在命令列中用 /-Y 參數
來覆蓋原有設定。

2010年10月2日 星期六

Java String 依照單字出現次數/頻率高的依序印出

功能:
依照每個單字出現的次數,由大到小,排列印出。

假設:
String oriString = "This is a book. That is a pencil"

輸出:
is 出現 2 次
a 出現 2 次
This 出現 1 次
That 出現 1 次
book 出現 1 次
pencil 出現 1 次

程式碼:
import java.util.regex.*;
import java.util.*;

public class StringSort {
 public static void main(String[] args){
  String oriString = "This is a book. That is a pencil.";
  Pattern p = Pattern.compile("\\w[^\\.\\s]*");
  Matcher m = p.matcher(oriString);
  
  Set<string> sortVerb = new TreeSet<string>();
  ArrayList<string> strArray = new ArrayList<string>();
  while(m.find()){
   strArray.add(m.group());
   sortVerb.add(m.group());
  }

  //計算oriString中的各個單字的次數
  int[] verbCount = new int[sortVerb.size()];
  int index = 0;
  for(String s : sortVerb){
   int count = 0;
   for(String sr : strArray){
    if(s.equals(sr))
     count++;
   }
   verbCount[index++] = count;
  }

  //開始排序
  int[] indexArray = new int[sortVerb.size()];
  for(int i = 0; i < indexArray.length; i++)
   indexArray[i] = i;
  int temp, indexTemp;
  index = 0;
  for (int f = 1; f < sortVerb.size(); f++) {
      if (verbCount[f] < verbCount[f-1])
       continue;
      temp = verbCount[f];
      indexTemp = indexArray[f];
      index = f-1;
      while ((index >= 0)&&(verbCount[index] < temp)) {
       verbCount[index+1] = verbCount[index];
       indexArray[index+1] = indexArray[index];
       index--;
      }
      verbCount[index+1]=temp;
      indexArray[index+1] = indexTemp;
  }
  Object[] printStr = sortVerb.toArray();
  for(int i = 0; i < indexArray.length; i++)
   System.out.println(printStr[indexArray[i]].toString()+"出現 "+verbCount[i]+"次");
 }
}

執行結果:
a出現 2次
is出現 2次
That出現 1次
This出現 1次
book出現 1次
pencil出現 1次

Linking-List Implement

[轉載] from: http://www.cnblogs.com/oomusou/archive/2008/03/22/1117686.html
Abstraction
使用C語言簡單的實現linked list,並用C++的std::vector實作出相同的功能作比較。
Introduction
學習資料結構,第一個要學的就是linked list,本文示範最簡單的linked list實現,包含建立與顯示,可把它當成linked list的標準範本,畢竟步驟都差不多。
一個基本的問題:為什麼需要linked list?若要將大量資料存到記憶體,你會想到什麼?第一個想到的就是array,但C語言是個靜態語言,array必須事先宣告大小,這樣compiler才能進行最佳化,若到時候沒用這麼多記憶體,就白白浪費記憶體了。或許你會說array可以配合malloc()變成動態array,但前提是你必須告訴malloc()要建立多大的array,若連要建立多大的陣列也不確定,而是在run-time看有多少資料就建立多大,這時連malloc()的動態array也不能用了,此時就得靠linked list。
linked list是資料結構的基礎,基本上就是靠struct如火車車廂那樣連在一起,run-time有需要時,在動態掛一個struct上去。

For C語言:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SLEN 255

struct list {
  int  no;
  char name[SLEN];
  struct list *next;
};
int main() {
  int no;
  char s[255];
  struct list *head    = NULL;
  struct list *current = NULL;
  struct list *prev    = NULL;

  while(1) {
    printf("No. = ");
    scanf("%d", &no);
    if (no == 0)
      break;

    printf("Name = ");
    scanf("%s", s);

    current = (struct list *)malloc(sizeof(struct list));
    if (current == NULL)
      exit(EXIT_FAILURE);

    current->next = NULL;

    current->no = no;
    strncpy(current->name, s, SLEN -1);
    current->name[SLEN -1] = '\0';

    if (head == NULL)
      head = current;
    else
      prev->next = current;

    prev = current;
  }

  // display linked list
  current = head;
  while(current != NULL) {
    printf("No. = %d, Name = %s\n", current->no, current->name);
    current = current->next;
  }

  // free linked list
  current = head;
  while(current != NULL) {
    prev = current;
    current = current->next;
    free(prev);
  }
  return 0;
}
執行結果:
1
ssss
2
kkkk
3
gggg
4
llll
0
No. = Name = No. = Name = No. = Name = No. = Name = No. = No. = 1, Name = ssss
No. = 2, Name = kkkk
No. = 3, Name = gggg
No. = 4, Name = llll
好吧,我承認怪怪的,可以Work了!

For C++:
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class List {
public:
  int no;
  string name;
};

int main() {
  vector<list> vec;

  while(1) {
    List list;
    cout << "No. = ";
    cin >> list.no;

    if (list.no == 0)
      break;

    cout << "Name = ";
    cin >> list.name;

    vec.push_back(list);
  }

  vector<list>::iterator iter = vec.begin();
  for(; iter != vec.end(); ++iter)
    cout << "No. = " << iter->no << ", Name = " << iter->name << endl;
  return 0;
}

C++看起來簡單多了!

C語言指標範例(指標++)

C語言中最令初學者人頭大的指標,其實很容易記錯
指標的運算元順序是由右到左(書上寫的),實際來測試一下

#include<stdio.h>
int data[2] = {100,200};
int moredata[2] = {300,400};
int main(void){
 int * p1, * p2, * p3;
 p1 = p2 = data;
 p3 = moredata;
 printf(" *p1 = %d, *p2 = %d, *p3= %d\n",
   *p1, *p2, *p3);
 printf(" *p1 = %d, *p2 = %d, *p3= %d\n",
   *p1++, *++p2, (*p3)++);
 printf(" *p1 = %d, *p2 = %d, *p3= %d\n",
   *p1, *p2, *p3);
 //括號測試
 printf("It is equal result...\n");
 p1 = p2 = data;
 p3 = moredata;
 printf(" *p1 = %d, *p2 = %d, *p3= %d\n",
    *(p1++), *(++p2), (*p3)++);
 printf(" *p1 = %d, *p2 = %d, *p3= %d\n",
   *p1, *p2, *p3);
  return 0;
}

*p1 = 100, *p2 = 100, *p3= 300
 *p1 = 100, *p2 = 200, *p3= 300
 *p1 = 200, *p2 = 200, *p3= 301
It is equal result...
 *p1 = 100, *p2 = 200, *p3= 301
 *p1 = 200, *p2 = 200, *p3= 302

由此得知,*p1++ 相等於 *(p1++)
而不是(*p)++,我之前記錯了><

C/C++[微小位元][數字&數字]

最近,因為面試的關係,想把一些東西弄清楚,所以做了一些測試:
以下是微小位元的測試,實際是就是二進位運算啦,考是算錯(怪怪)

#include<stdio.h>

int main(void){
  int a = 44;
  int b = 55;
  int c = 33;
  int d = -20;
  printf("uni-micro operator: \n");
  printf("a & b = %d\n", a & b);
  printf("b & c = %d\n", b & c);
  printf("c & d = %d\n", c & d);
  printf("b & b = %d\n", b & b);
  printf("a | b = %d\n", a | b);

  printf("double-micro operator: \n");
  printf("a && b = %d\n", a && b);
  printf("a || b = %d\n", a || b);

  printf("while-micro operator: \n");
  while( a & b){
   printf("a ^ b = %d, ", a ^ b);
   a--;
   if(a < 40){
    break;
   }
  }
  printf("\n");
  while( a ^ d){
     printf("a ^ d = %d, ", a ^ d);
     a--;
     if( a ^ d < 0){
      break;
     }
  }

  return 0;
}
結果:
uni-micro operator: 
a & b = 36
b & c = 33
c & d = 32
b & b = 55
a | b = 63
double-micro operator: 
a && b = 1
a || b = 1
while-micro operator: 
a ^ b = 27, a ^ b = 28, a ^ b = 29, a ^ b = 30, a ^ b = 31, 
a ^ d = -53, 

由結果知道,while迴圈對負號的數值也會進入迴圈跑,我之前已為負的就不會跑= ="
學習中...

2010年2月2日 星期二

解決C/C++中的multiple definition of問題

範例:
main.cpp

#include "global.h" 
int Main(....) { ... }

file_1.cpp

#include "global.h"
....

file_1.cpp

#include "global.h" 

global.h中寫有所有的全局變量及其初始化值和函數聲明
在編譯的時候就會出錯: first defined here multiple definition of
原因是因為在多次包含global.h時重複定義了變量和函數。
解決方法: 


方法一:

在global.c(或.cpp) 中聲明變量(不初始化),然後頭文件global.h中在所有的變量聲明前加上extern 如 extern int flag; 然後在其他需要使用全局變量的cpp文件中包含.h 文件而不要包含.cpp 文件。編譯器會為global.cpp 生成目標文件,然後連接時,在使用全局變量的文件中就會連接到此文件。 

範例:

Declare.h:
#ifndef DECLARE_H
#define DECLARE_H
extern const char *COMP;
#endif

subprog.cpp:
#include 
#include "Declare.h"
const char *COMP="macromedia";

void ShowComp() {
std::cout << COMP << std::endl;
}
main.cpp:
#include "Declare.h"
extern void ShowComp();
int main(int agrc, char *argv[]) {
ShowComp();
return 0;
}
方法二: 在global.h中加入防止多次重複定義的宏判斷符號 你的.H裡面要加上條件編譯 #ifndef GLOBAL #define GLOBAL XXXXX XXXXX  ...................... #endif   記住:在ifndef時一定要在第一行,前邊不要有任何的註釋或語句。

2010年1月26日 星期二

vector傳遞/宣告(struct/物件)以及iterator 範例

轉載[http://www.cnblogs.com/oomusou/archive/2008/08/01/vector_struct.html]

Abstract
一個很常見的需求:『將struct塞進vector』,在C++該怎麼做呢?
Introduction
使用環境:Visual C++ 9.0 / Visual Studio 2008

由於vector只允許一個欄位,所以才會想將struct塞進vector,以彌補vector的不足。
struct_in_vector.cpp / C++
/*
  (C) OOMusou 2008 http://oomusou.cnblogs.com
 
  Filename    : struct_in_vector.cpp
  Compiler    : Visual C++ 9.0 / Visual Studio 2008
  Description : Demo how to insert struct in vector
  Release     : 08/01/2008 1.0
  */

 #include <iostream>
 #include <vector>
 #include <string>

 using namespace std;
 
 struct Student {
   int  id;
   string name;
 };
 
 int main() {
   vector svec;
   
   struct Student master;
   master.id = 1;
   master.name = "clare";
   svec.push_back(master);
   
   master.id = 2;
   master.name = "jingyi";
   svec.push_back(master);
   
   master.id = 3;
   master.name = "jessie";
   svec.push_back(master);
   
   vector::iterator iter = svec.begin();
   for(iter; iter != svec.end(); ++iter)
     cout << iter->id << " " << iter->name << endl;
 }
執行結果
clare
jingyi
jessie
由於vector內放的是struct,所以push_back()要塞個也是struct,而不能針對struct的member來塞。因此要先宣告一個暫存的struct做中介。
以上的code,看起來都是push_back()同一個master object,這樣沒有問題嗎?因為push_back()進vector是採用copy的方式,會產生一個新的副本,所以才可以這樣使用。

vector內元件刪除

 C++中 vector內元素刪除的方法分為兩個~
方法1:
vector<AA>::iterator ite;
for ( ite = vaa.begin(); ite != vaa.end(); )
{
    if (find(intList.begin(), intList.end(),ite->n) != intList.end())
        vaa.erase(++ite);
    else
        ++ite;
}


方法2:
vector<AA>::iterator ite = vaa.begin();
for (ite = vaa.begin(); ite != vaa.end(); ++ite )
{
    if (find(intList.begin(), intList.end(),ite->n) != intList.end())
        vaa.erase(ite);
}

當vector內是物件或是struct時,以上的方法可能會有錯誤,這是因為當
erase時,iterator就會失效,因此可以用下面的方式解決

方法3:
struct AA{
    int a;
    int b;
    int (int x, y){a=x;b=y;}

}

vector<struct AA>::iterator ite = vaa.begin();
for (ite = vaa.begin(); ite != vaa.end(); ++ite )
{
    if (判斷式)
        ite = vaa.erase(ite);
    else
        ++ite;
}

簡單的方法大致如上,其實有其他更好的方法,不過有些複雜像是if_find搭
配#include裡面所定義的方法可以讓vector<物件>刪除更容易

2010年1月23日 星期六

Java判斷作業系統與檔案路徑

如何在java程式中判斷幕前作業系統是何種作業系統
以下位範例程式:
public class OSValidator {

    public static void main(String[] args) {
        if (isWindows()) {
            System.out.println("This is Windows");
        } else if (isMac()) {
            System.out.println("This is Mac");
        } else if (isUnix()) {
            System.out.println("This is Unix or Linux");
        } else {
            System.out.println("Your OS is not support!!");
        }
    }

    public static boolean isWindows() {

        String os = System.getProperty("os.name").toLowerCase();
//windows
        return (os.indexOf("win") >= 0);

    }

    public static boolean isMac() {

        String os = System.getProperty("os.name").toLowerCase();
//Mac
        return (os.indexOf("mac") >= 0);

    }

    public static boolean isUnix() {

        String os = System.getProperty("os.name").toLowerCase();
//linux or unix
        return (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0);

    }
}
System.getProperty("os.name") 在java程式中判斷此作業系統是Linux或Windows
在Ubuntu的作業系統中,測試取的的字串為Linux,vista則為Windows。


System.getProperty("file.separator")  => 使用時機是在需要用到路徑的時候,Windows使用 "\\",或Linux使用 "/"
來建立檔案或資料夾路徑。