2025/03/09

C++ 學習筆記

C++ 設計原則

Bjarne Stroustrup 博士在 20 世紀 80 年代在貝爾實驗室工作期間發明並實現了 C++。 一開始的想法可以追溯到 1979 年,起初這種語言被稱作「C with Classes」,作為 C 語言的增強版出現。 C++ 在 C 的基礎上增加功能,並且儘量與 C 的相容。 C++ 比起其它語言有巨大優勢的地方,就是可以直接使用 C 的函式。

C++ 編譯器自由軟體的主要實作為 GNU Compiler Collection (GCC) 與 Clang

C++ 是一個通用的語言,抽象資料型別為 C++ 的核心概念, 含有一些系統程式領域的特性,並且期望能夠達到下列的目標:

  • is a better C
  • supports data abstraction
  • supports object-oriented programming
  • supports generic programming
在《C++語言的設計和演化》(1994)中,Bjarne Stroustrup 描述了他在設計C++時,所使用的一些原則。
  • C++ 設計成靜態類型、和 C同樣高效率且可移植的多用途程式設計語言。
  • C++ 設計成直接的和廣泛的支援多種程式設計風格。
  • C++ 設計成給程式設計者更多的選擇,即使可能導致程式設計者選擇錯誤。
  • C++ 設計成盡可能與 C 相容,籍此提供一個從 C 到 C++ 的平滑過渡。
  • C++ 避免平臺限定或沒有普遍用途的特性。
  • C++ 不使用會帶來額外開銷的特性。
  • C++ 設計成無需複雜的程式設計環境。

但是,C++ 標準並沒有規範 Object Model 的實作方式,同時 C++ 也缺乏 ABI 的標準, 因此在 Windows Platform 上各家編譯器所產出的 DLL 很難互通,這是 C++ 在 binary level 上的缺點。


下面是一個 C 的 Hello World 程式:

#include <stdio.h>

int main() {
   /* my first program in C */
   printf("Hello, World! \n");

   return 0;
}

In a C program, the semicolon is a statement terminator. That is, each individual statement must be ended with a semicolon. It indicates the end of one logical entity.

C++標準表頭檔沒有副檔名,因為副檔名的命名規則隨各編譯器而有所不同。 下面是 C++ 版的 Hello World:

#include <iostream>

int main() {
    std::cout << "Hello! World!\n";

    return 0;
}

下面是一個範例,使用者在命令列輸入一個字串,然後程式計算字串 MD5 的值並且輸出:

//
// g++ test.cpp -std=c++17 -lcrypto
//
#include <cstring>
#include <string>
#include <iostream>
#include <openssl/md5.h>

std::string MD5(const std::string &src)
{
    MD5_CTX ctx;

    std::string md5_string;
    unsigned char md[16] = {0};
    char tmp[3] = {0};

    MD5_Init(&ctx);
    MD5_Update(&ctx, src.c_str(), src.size());
    MD5_Final(md, &ctx);

    for (int i = 0; i < 16; ++i)
    {
        memset(tmp, 0x00, sizeof(tmp));
        snprintf(tmp, sizeof(tmp), "%02X", md[i]);
        md5_string += tmp;
    }

    return md5_string;
}

int main(int argc, char *argv[])
{
    if (argc == 1)
    {
        std::cout << "Please give a string." << std::endl;
    }
    else
    {
        std::string mystring = argv[1];
        std::cout << "String: " << mystring << std::endl;
        std::cout << "Result: " << MD5(mystring) << std::endl;
    }
    return 0;
}

下面是一個範例,使用者在命令列輸入一個字串,然後程式計算字串 SHA256 的值並且輸出:

//
// g++ test.cpp -std=c++17 -lcrypto
//
#include <cstring>
#include <string>
#include <iostream>
#include <openssl/sha.h>

std::string SHA256(const std::string &src)
{
    SHA256_CTX ctx;

    std::string sha256_string;
    unsigned char md[32] = {0};
    char tmp[3] = {0};

    SHA256_Init(&ctx);
    SHA256_Update(&ctx, src.c_str(), src.size());
    SHA256_Final(md, &ctx);

    for (int i = 0; i < 32; ++i)
    {
        memset(tmp, 0x00, sizeof(tmp));
        snprintf(tmp, sizeof(tmp), "%02X", md[i]);
        sha256_string += tmp;
    }

    return sha256_string;
}

int main(int argc, char *argv[])
{
    if (argc == 1)
    {
        std::cout << "Please give a string." << std::endl;
    }
    else
    {
        std::string mystring = argv[1];
        std::cout << "String: " << mystring << std::endl;
        std::cout << "Result: " << SHA256(mystring) << std::endl;
    }
    return 0;
}

Date types

C++ 中基本的資料型態主要區分為「整數」(Integer)、「浮點數」(Float)、「字元」(Character),而這幾種還可以細分:

  • 整數:用 來表示整數值,可以區分為 short、int 與 long,可容納的大小各不相同,short的長度為半個 word,int 表示一個 word, 而 long 可能是一個或兩個 word(要看採用的 data model),在 32 位元機器上 int 與 long 的長度通常是相同的, 型態的長度越長,表示可表示的整數值範圍越大。 如果是 64 位元的機器 (64-bit computing), 大多數的 UNIX 系統在 64 位元採用 LP64 data model,這時候 long 就會是 8 bytes。 而 Windows 64 位元採用 LLP64 這個 data model,這時候 long 的大小仍然還是 4 bytes,也就是差異出現在 long 這個型別上。
  • 浮點數:用來表示小數值,可以區分為 float、double 與 long double,float 的長度為一個 word,double 的長度為二個 word, long double 長度為 3 或 4 個word。
  • 字元:用來儲存字元,長度為 1 個位元組,其字元編碼主要依 ASCII 表而來,由於字元在記憶體中所佔有的空間較小, 所以它也可以用來儲存較小範圍的整數。

以上的資料型態在記憶體中所佔有的大小依平台系統而有所差異,word 的大小取決於機器,在 32 位元機器上通常一個 word 是 4 個位元組, 如果想要知道這些資料型態在所使用的平台上所佔有的記憶體空間有多少,最好的作法是使用 sizeof() 運算子,取得確實的記憶體大小。

在 C11 標準中,建議包括 stdint.h 程式庫(亦包含在 C++ 的標準函式庫), 使用 int8_tint16_tint32_tint64_tuint8_tuint16_tuint32_tuint64_t 等作為整數型態的宣告,以避免平台相依性的問題。

有時候我們需要表示非十進位的數字(例如八進位或者十六進位)。 在 C 其八進位通常以「0」開頭(注意是數字 0),例如 0640;而十六進位通常以「0x」或「0X」開頭,例如 0xEF 或 0XEF; 而二進位通常以「0b」開頭,例如 0b1。

要注意的是,如果是需要精確求值的場合,那麼需要考慮使用 big number library 來實作,而不是使用浮點數。 有些程式語言(例如 Tcl、Common Lisp 等)直接支援大整數運算,無需顯式地使用 API。 使用浮點數有兩個最根本的問題:輸入與儲存的值不一定精確計算的結果會有誤差

另外,電腦的浮點數常用二進位或十六進位運算與儲存,所以在程式中的十進位數需要轉換為二進位或十六進位, 但是一個簡單的十進位數卻可能轉換成無限位的二進位或十六進位數,而儲存的位置是有限的, 算出來的結果就不夠精確,結果也可能受到四捨五入誤差的影響,如果再用來計算其它值,誤差就會愈滾愈大。


There are two kinds of expressions in C −

  • lvalue − Expressions that refer to a memory location are called "lvalue" expressions. An lvalue may appear as either the left-hand or right-hand side of an assignment.
  • rvalue − The term rvalue refers to a data value that is stored at some address in memory. An rvalue is an expression that cannot have a value assigned to it which means an rvalue may appear on the right-hand side but not on the left-hand side of an assignment.

Constants refer to fixed values that the program may not alter during its execution. These fixed values are also called literals.

Constants can be of any of the basic data types like an integer constant, a floating constant, a character constant, or a string literal.

There are two simple ways in C to define constants −

  • Using #define preprocessor.
  • Using const keyword.

Given below is the form to use #define preprocessor to define a constant −

#define identifier value

The following example explains it in detail −

#include <stdio.h>

#define LENGTH 10
#define WIDTH  5
#define NEWLINE '\n'

int main() {
   int area;

   area = LENGTH * WIDTH;
   printf("value of area : %d", area);
   printf("%c", NEWLINE);

   return 0;
}

You can use const prefix to declare constants with a specific type as follows −

const type variable = value;

The following example explains it in detail −

#include <stdio.h>

int main() {
   const int  LENGTH = 10;
   const int  WIDTH = 5;
   const char NEWLINE = '\n';
   int area;

   area = LENGTH * WIDTH;
   printf("value of area : %d", area);
   printf("%c", NEWLINE);

   return 0;
}

Macros in C and C++ are tokens that are processed by the preprocessor before compilation. Each instance of a macro token is replaced with its defined value or expression before the file is compiled. Macros are commonly used in C-style programming to define compile-time constant values. However, macros are error-prone and difficult to debug. In modern C++, you should prefer constexpr variables for compile-time constants:

#define SIZE 10 // C-style
constexpr int size = 10; // modern C++

constexpr 可以說是 C++11 對 const 修飾字的加強。 常數表達式 (constant expression) 代表的是可以在編譯時期經過固定確定運算得到確切值的表達式。


A storage class defines the scope (visibility) and life-time of variables and/or functions within a C Program. They precede the type that they modify. We have four different storage classes in a C program −

  • auto
  • register
  • static
  • extern

The auto storage class is the default storage class for all local variables.

{
   int mount;
   auto int month;
}

The register storage class is used to define local variables that should be stored in a register instead of RAM.

{
   register int  miles;
}

The static storage class instructs the compiler to keep a local variable in existence during the life-time of the program instead of creating and destroying it each time it comes into and goes out of scope. Therefore, making local variables static allows them to maintain their values between function calls.

The extern storage class is used to give a reference of a global variable that is visible to ALL the program files. When you use 'extern', the variable cannot be initialized however, it points the variable name at a storage location that has been previously defined.


Arrays a kind of data structure that can store a fixed-size sequential collection of elements of the same type. An array is used to store a collection of data, but it is often more useful to think of an array as a collection of variables of the same type.

You can initialize an array in C either one by one or using a single statement as follows −

double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

If you omit the size of the array, an array just big enough to hold the initialization is created. Therefore, if you write −

double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};

A pointer is a variable whose value is the address of another variable, i.e., direct address of the memory location. Like any variable or constant, you must declare a pointer before using it to store any variable address.

#include <stdio.h>

int main () {

   int  var = 20;   /* actual variable declaration */
   int  *ip;        /* pointer variable declaration */

   ip = &var;  /* store address of var in pointer variable*/

   printf("Address of var variable: %x\n", &var  );

   /* address stored in pointer variable */
   printf("Address stored in ip variable: %x\n", ip );

   /* access the value using the pointer */
   printf("Value of *ip variable: %d\n", *ip );

   return 0;
}

It is always a good practice to assign a NULL value to a pointer variable in case you do not have an exact address to be assigned. This is done at the time of variable declaration. A pointer that is assigned NULL is called a null pointer.

Arrays are not pointers! Arrays look like pointers, and pointers can refer to array objects. For example, people sometimes think that char s[] is identical to char *s. But they aren’t identical. The array declaration char s[12] requests that space for 12 characters be set aside, to be known by the name s. The pointer declaration char *p, on the other hand, requests a place that holds a pointer, to be known by the name p. This pointer can point to almost anywhere: to any char, to any contiguous array of chars, or frankly nowhere.


參考(Reference)是 C++ 新增加的語言特性,為物件的別名(Alias),也就是替代名稱,對參考名稱存取時該有什麼行為, 都參考了來源物件該有的行為,在 C++ 中,「物件」這個名詞,不單只是指類別的實例,而是指記憶體中的一塊資料。

要定義參考,是在型態關鍵字後加上 & 運算子,例如:

int n = 10;
int *p = &n;
int &r = n;

上面的程式中,最後一行定義參考。參考一定要初始化,否則無法通過編譯。 與指標 (pointer) 不同,參考在初始化之後不能參照不同的物件,或設為 null,也因此參考一般而言比指標安全。


C 並沒有為 String 定義一個型別,字串在 C 語言中是一個以 null character '\0' 為結尾的一維陣列。 這讓 C 的字串需要小心的處理。

如果要在 C 進行字串串接,可以使用 asprintf,雖然是 GNU 自行擴充的 function,但是使用上很方便。

#define _GNU_SOURCE
#include <stdio.h>

下面則是使用的例子:

char *s;
asprintf(&s,"hello,%s","-Reader-");
printf("%s\n",s);
if (s) free(s);

C++ 在這一點則有所改變,加入了 std::string 作為字串物件類別。


Arrays allow to define type of variables that can hold several data items of the same kind. Similarly structure is another user defined data type available in C that allows to combine data items of different kinds.

To define a structure, you must use the struct statement. The struct statement defines a new data type, with more than one member. The format of the struct statement is as follows −

struct [structure tag] {

   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];

The structure tag is optional and each member definition is a normal variable definition, such as int i; or float f; or any other valid variable definition. At the end of the structure's definition, before the final semicolon, you can specify one or more structure variables but it is optional. Here is the way you would declare the Book structure −

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

An enum is a special type that represents a group of constants (unchangeable values).

下面是一個 enum 的例子:

enum Level {
  LOW,
  MEDIUM,
  HIGH
}; 

下面就是宣告變數並且初始化的例子:

enum Level myVar = MEDIUM;

「Scoped and strongly typed enums」是 C++11 時所引進的一個新的功能,主要是要取代舊的列舉型別(enum)。 基本用法是在 enum 後面,再加上 class 或 struct;而要使用定義的值的時候,一定要加上範圍(scope、在這裡就是指 class 的名稱)。

enum class EColor
{
    RED,
    GREEN,
    BLUE
};

EColor eColor = EColor::RED;

另外,在 C++11 開始,不管是 enum 或 enum class,也都可以指定實際要使用的型別。

enum class EColor : char
{
  RED,
  GREEN,
  BLUE
};

A union is a special data type available in C that allows to store different data types in the same memory location. You can define a union with many members, but only one member can contain a value at any given time. Unions provide an efficient way of using the same memory location for multiple-purpose.

To define a union, you must use the union statement in the same way as you did while defining a structure. The union statement defines a new data type with more than one member for your program. The format of the union statement is as follows −

union [union tag] {
   member definition;
   member definition;
   ...
   member definition;
} [one or more union variables];

The union tag is optional and each member definition is a normal variable definition, such as int i; or float f; or any other valid variable definition. At the end of the union's definition, before the final semicolon, you can specify one or more union variables but it is optional. Here is the way you would define a union type named Data having three members i, f, and str −

union Data {
   int i;
   float f;
   char str[20];
} data;

Now, a variable of Data type can store an integer, a floating-point number, or a string of characters. It means a single variable, i.e., same memory location, can be used to store multiple types of data. You can use any built-in or user defined data types inside a union based on your requirement.

The memory occupied by a union will be large enough to hold the largest member of the union. For example, in the above example, Data type will occupy 20 bytes of memory space because this is the maximum space which can be occupied by a character string.


The declaration of a bit-field has the following form inside a structure −

struct {
   type [member_name] : width ;
};

The variables defined with a predefined width are called bit fields. A bit field can hold more than a single bit; for example, if you need a variable to store a value from 0 to 7, then you can define a bit field with a width of 3 bits as follows −

struct {
   unsigned int age : 3;
} Age;

The C programming language provides a keyword called typedef, which you can use to give a type a new name. Following is an example to define a term BYTE for one-byte numbers −

typedef unsigned char BYTE;

You can use typedef to give a name to your user defined data types as well. For example, you can use typedef with structure to define a new data type and then use that data type to define structure variables directly as follows −

#include <stdio.h>
#include <string.h>

typedef struct Books {
   char title[50];
   char author[50];
   char subject[100];
   int book_id;
} Book;

int main( ) {

   Book book;

   strcpy( book.title, "C Programming");
   strcpy( book.author, "Nuha Ali");
   strcpy( book.subject, "C Programming Tutorial");
   book.book_id = 6495407;

   printf( "Book title : %s\n", book.title);
   printf( "Book author : %s\n", book.author);
   printf( "Book subject : %s\n", book.subject);
   printf( "Book book_id : %d\n", book.book_id);

   return 0;
}

The C Preprocessor is not a part of the compiler, but is a separate step in the compilation process. In simple terms, a C Preprocessor is just a text substitution tool and it instructs the compiler to do required pre-processing before the actual compilation. We'll refer to the C Preprocessor as CPP.

All preprocessor commands begin with a hash symbol (#). It must be the first nonblank character, and for readability, a preprocessor directive should begin in the first column.

ANSI C defines a number of macros.

#include <stdio.h>

int main() {

   printf("File :%s\n", __FILE__ );
   printf("Date :%s\n", __DATE__ );
   printf("Time :%s\n", __TIME__ );
   printf("Line :%d\n", __LINE__ );
   printf("ANSI :%d\n", __STDC__ );

}

The token-pasting operator (##) within a macro definition combines two arguments. It permits two separate tokens in the macro definition to be joined into a single token. For example −

#include <stdio.h>

#define tokenpaster(n) printf ("token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;
   tokenpaster(34);
   return 0;
}

A header file is a file with extension .h which contains C function declarations and macro definitions to be shared between several source files. There are two types of header files: the files that the programmer writes and the files that comes with your compiler.

You request to use a header file in your program by including it with the C preprocessing directive #include, like you have seen inclusion of stdio.h header file, which comes along with your compiler.

Including a header file is equal to copying the content of the header file but we do not do it because it will be error-prone and it is not a good idea to copy the content of a header file in the source files, especially if we have multiple source files in a program.

A simple practice in C or C++ programs is that we keep all the constants, macros, system wide global variables, and function prototypes in the header files and include that header file wherever it is required.

If a header file happens to be included twice, the compiler will process its contents twice and it will result in an error. The standard way to prevent this is to enclose the entire real contents of the file in a conditional, like this −

#ifndef HEADER_FILE
#define HEADER_FILE

the entire header file file

#endif

Control flow

C 語言用來判斷條件的 statement 有二個,ifswitch。 另外還有條件運算子 ? : 這個運算子。

Exp1 ? Exp2 : Exp3;

C 語言迴圈包含了 while, fordo ... while 等三種迴圈。


Write a program that displays the digits from 1 to n then back down to 1; for instance, if n = 5, the program should display 123454321. You are permitted to use only a single for loop. The range is 0 < n < 10.

首先是使用 switch 來解:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    int n = 0;

    if (argc >= 2) {
        n = atoi(argv[1]);
    } else {
        fprintf(stderr, "Please give a number.\n");
        return 1;
    }

    if (n < 1 || n > 9) {
        fprintf(stderr, "Out of range.\n");
        return 1;
    }

    switch (n) {
    case 1:
        printf("1\n");
        break;
    case 2:
        printf("121\n");
        break;
    case 3:
        printf("12321\n");
        break;
    case 4:
        printf("1234321\n");
        break;
    case 5:
        printf("123454321\n");
        break;
    case 6:
        printf("12345654321\n");
        break;
    case 7:
        printf("1234567654321\n");
        break;
    case 8:
        printf("123456787654321\n");
        break;
    case 9:
        printf("12345678987654321\n");
        break;
    default:
        printf("Please input 0 < n < 10\n");
        break;
    }

    return 0;
}

接下來,改為使用 while 的版本:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    int n = 0;

    if (argc >= 2) {
        n = atoi(argv[1]);
    } else {
        fprintf(stderr, "Please give a number.\n");
        return 1;
    }

    if (n < 1 || n > 9) {
        fprintf(stderr, "Out of range.\n");
        return 1;
    }

    int positive = 1;
    int count = 0;
    while (1) {
        if (positive == 1) {
            count++;
            printf("%d", count);
            if (count == n) {
                positive = 0;
                continue;
            }
        } else {
            count--;
            if (count > 0) {
                printf("%d", count);
            } else {
                break;
            }
        }
    }
    printf("\n");

    return 0;
}

C++ 的控制結構大致上與 C 相同,在 C++11 增加了以範圍為基礎的 for 陳述式。

#include <iostream>

int main() {

    for (int i : {1, 2, 3}) {
        std::cout << i << std::endl;
    }

    return 0;
}

Function

函式 (Function) 的組成主要包括四個部份:返回值、函式名稱、參數列與函式主體。前三者稱為函式宣告或函式原型(Function prototype), 在 C++ 中規定,如果函式是在 main 之後實作,必須在 main 之前進行宣告,否則會出現編譯錯誤。

如果函式不傳回任何值,則宣告為 void,若不傳入任何引數,參數列保持空白即可,雖然也可以使用 void 來加以註明, 要注意的是 void 註明參數列不使用為是 C 的風格,而在 C++ 中,參數列空白就表示這個函式不接受任何引數。

在含入標頭檔時,若標頭檔與含入標頭檔的文件在同一目錄,就使用雙引號 " " 來包括標頭檔名稱,如果是標準或專案專屬的標頭檔,例如 C++ 的標準表頭檔,那麼使用角括號 < > 來括住,編譯器在尋找時就會從設定的目錄尋找。

下面是 C 語言對函式的參數沒有固定數目時的方法。

#include <stdio.h>
#include <stdarg.h>

double average(int num,...) {

   va_list valist;
   double sum = 0.0;
   int i;

   /* initialize valist for num number of arguments */
   va_start(valist, num);

   /* access all the arguments assigned to valist */
   for (i = 0; i < num; i++) {
      sum += va_arg(valist, int);
   }

   /* clean memory reserved for valist */
   va_end(valist);

   return sum/num;
}

int main() {
   printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
   printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
}

C 語言在 <stdlib.h> 定義了關於記憶體管理的函式,例如 malloc, realloc 與 free。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

   char name[100];
   char *description = NULL;

   strcpy(name, "Zara Ali");

   /* allocate memory dynamically */
   description = (char *) malloc( 200 * sizeof(char) + 1);

   if( description == NULL ) {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   } else {
      strcpy( description, "Zara ali a DPS student in class 10th");
   }

   printf("Name = %s\n", name );
   printf("Description: %s\n", description );

   /* Free memory */
   if(description) free(description);
}

下面是人類猜數字的小遊戲:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int getA(char *ans, char *guess) {
  int len1 = 0;
  int len2 = 0;
  int count = 0;

  len1 = strlen(ans);
  len2 = strlen(guess);

  if (len1 != len2) {
    return 0;
  }

  for (int i = 0; i < len1; i++) {
    if (ans[i] == guess[i]) {
      count++;
    }
  }

  return count;
}

int getB(char *ans, char *guess) {
  int len1 = 0;
  int len2 = 0;
  int count = 0;

  len1 = strlen(ans);
  len2 = strlen(guess);

  if (len1 != len2) {
    return 0;
  }

  for (int i = 0; i < len1; i++) {
    for (int j = 0; j < len2; j++) {
      if (i != j) {
        if (ans[i] == guess[j]) {
          count++;
        }
      }
    }
  }

  return count;
}

int main() {
  int answer = 1;
  char ans[5];
  char guess[5];
  int avalue = 0;
  int bvalue = 0;

  srand(time(0));

  while (1) {
    answer = (int)(rand() % 9999);
    sprintf(ans, "%04d", answer);

    if (ans[0] != ans[1] && ans[0] != ans[2] && ans[0] != ans[3] &&
        ans[1] != ans[2] && ans[1] != ans[3] && ans[2] != ans[3]) {
      break;
    }
  }

  while (1) {
    printf("Please input your guess: ");
    scanf("%s", guess);
    avalue = getA(ans, guess);
    bvalue = getB(ans, guess);
    printf("Result: A = %d, B = %d\n", avalue, bvalue);

    if (avalue == 4 && bvalue == 0) {
      printf("Game is completed.\n");
      break;
    }

    printf("\n");
  }
}

下面是電腦猜數字的小遊戲:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int getA(char *ans, char *guess) {
  int len1 = 0;
  int len2 = 0;
  int count = 0;

  len1 = strlen(ans);
  len2 = strlen(guess);

  if (len1 != len2) {
    return 0;
  }

  for (int i = 0; i < len1; i++) {
    if (ans[i] == guess[i]) {
      count++;
    }
  }

  return count;
}

int getB(char *ans, char *guess) {
  int len1 = 0;
  int len2 = 0;
  int count = 0;

  len1 = strlen(ans);
  len2 = strlen(guess);

  if (len1 != len2) {
    return 0;
  }

  for (int i = 0; i < len1; i++) {
    for (int j = 0; j < len2; j++) {
      if (i != j) {
        if (ans[i] == guess[j]) {
          count++;
        }
      }
    }
  }

  return count;
}

int main() {
  int count = 0;
  int index = 0;
  char **total;
  char **total_new;
  char **newtotal;
  char ans[5];
  int avalue = 0;
  int bvalue = 0;

  total = (char **)malloc(sizeof(char *) * 5040);
  if (!total) {
    printf("Malloc failed.\n");
    return 0;
  }

  for (int i = 0; i <= 9; i++) {
    for (int j = 0; j <= 9; j++) {
      for (int k = 0; k <= 9; k++) {
        for (int m = 0; m <= 9; m++) {
          if (i != j && i != k && i != m && j != k && j != m && k != m) {
            char buffer[5] = {0};
            sprintf(buffer, "%d%d%d%d", i, j, k, m);
            total[count] = (char *)malloc(sizeof(char) * 5);
            strcpy(total[count], buffer);
            count++;
          }
        }
      }
    }
  }

  while (1) {
    if (count == 0) {
      printf("Something is wrong.\n");
      break;
    }

    strcpy(ans, total[0]);
    printf("My answer is %s.\n", ans);
    printf("The a value is: ");
    scanf("%d", &avalue);
    printf("The b value is: ");
    scanf("%d", &bvalue);

    if (avalue == 4 && bvalue == 0) {
      printf("Game is completed.\n");
      break;
    }

    index = 0;
    newtotal = (char **)malloc(sizeof(char *) * count);
    for (int i = 0; i < count; i++) {
      int aguess = 0;
      int bguess = 0;
      aguess = getA(total[i], ans);
      bguess = getB(total[i], ans);

      if (aguess == avalue && bguess == bvalue) {
        newtotal[index] = (char *)malloc(sizeof(char) * 5);
        strcpy(newtotal[index], total[i]);
        index++;
      }
    }

    total_new = (char **)realloc(total, sizeof(char *) * index);
    if (!total_new) {
        printf("Realloc failed.\n");
        break;
    }
    total = total_new;

    for (int i = 0; i < index; i++) {
      strcpy(total[i], newtotal[i]);
    }

    for (int i = 0; i < index; i++) {
      if (newtotal[i]) {
        free(newtotal[i]);
      }
    }
    if (newtotal) {
      free(newtotal);
    }

    count = index;
    printf("\n");
  }

  for (int i = 0; i < count; i++) {
    if (total[i])
      free(total[i]);
  }

  if (total) {
    free(total);
  }
}

realloc 的行為要特別注意,如果失敗會傳回 NULL,但是原本配置的記憶體並不會釋放!所以需要特別處理。

C++ Class

變數(Variable)提供一個有名稱的記憶體儲存空間,一個變數關係至一個資料型態,一個變數本身的值與一個變數的位址值。 變數資料型態決定了變數所分配到的記憶體大小;變數本身的值是指儲存於記憶體中的某個數值,而您可以透過變數名稱取得這個數值, 這個數值又稱為 rvalue或 read value;而變數的位址值則是指變數所分配到的記憶體之位置,變數本身又稱為lvalue或 location value。

由於 C++ 的演化來自 C,在 C++ 中的術語物件和 C 語言一樣是意味著記憶體區域,而不是類別實體。在 class 中,有兩大成員,一是資料(data member),一是行為(member function)。

C++ 使用 new 和 delete 來建立和刪除物件,
string *stringPtr1 = new string;
delete stringPtr1;
下面是另外一個形式:
string *stringPtr1 = new string[100];
delete [] stringPtr1;
C++ 的 new 運算子和 C 的 malloc 函式都是為了要配置記憶體,但是 new 不但配置物件所需的記憶體空間,同時會引發建構式的執行。

雖然 new 運算子看起來是單一運算,但是包含了二個動作:
  1. 透過適當的 new 運算子函式實體,配置所需的記憶體(new 運算子配置所需的記憶體實作上幾乎都是以標準的 C malloc() 來完成,正如 delete 運算子是以 C free() 來完成)
  2. 將所配置的物件設立初值

Brace initialization

It is not always necessary to define a constructor for a class, especially ones that are relatively simple. Users can initialize objects of a class or struct by using uniform initialization, as shown in the following example:

// no_constructor.cpp
// Compile with: cl /EHsc no_constructor.cpp
#include <time.h>

// No constructor
struct TempData
{
    int StationId;
    time_t timeSet;
    double current;
    double maxTemp;
    double minTemp;
};

// Has a constructor
struct TempData2
{
    TempData2(double minimum, double maximum, double cur, int id, time_t t) :
       stationId{id}, timeSet{t}, current{cur}, maxTemp{maximum}, minTemp{minimum} {}
    int stationId;
    time_t timeSet;
    double current;
    double maxTemp;
    double minTemp;
};

int main()
{
    time_t time_to_set;

    // Member initialization (in order of declaration):
    TempData td{ 45978, time(&time_to_set), 28.9, 37.0, 16.7 };

    // Default initialization = {0,0,0,0,0}
    TempData td_default{};

    // Uninitialized = if used, emits warning C4700 uninitialized local variable
    TempData td_noInit;

    // Member declaration (in order of ctor parameters)
    TempData2 td2{ 16.7, 37.0, 28.9, 45978, time(&time_to_set) };

    return 0;
}

Note that when a class or struct has no constructor, you provide the list elements in the order that the members are declared in the class. If the class has a constructor, provide the elements in the order of the parameters. If a type has a default constructor, either implicitly or explicitly declared, you can use default brace initialization (with empty braces).

For example, the following class may be initialized by using both default and non-default brace initialization:

#include <string>
using namespace std;

class class_a {
public:
    class_a() {}
    class_a(string str) : m_string{ str } {}
    class_a(string str, double dbl) : m_string{ str }, m_double{ dbl } {}
double m_double;
string m_string;
};

int main()
{
    class_a c1{};
    class_a c1_1;

    class_a c2{ "ww" };
    class_a c2_1("xx");

    // order of parameters is the same as the constructor
    class_a c3{ "yy", 4.4 };
    class_a c3_1("zz", 5.5);
}

If a class has non-default constructors, the order in which class members appear in the brace initializer is the order in which the corresponding parameters appear in the constructor, not the order in which the members are declared (as with class_a in the previous example).

靜態變數與函式

static 成員變數不屬於物件的一部份,而是類別的一部份,所以可以在沒有建立任何物件的情況下就處理 static 成員變數。而且即使 static 成員變數的權限為 private,設定 static 成員變數初值時,不受任何存取權限的束縛。

static 成員函式和 static 成員變數一樣,可以在沒有建立任何物件的情況下就被呼叫執行。 而之所以可以在未建立任何物件的情況下就被呼叫執行, 是因為編譯器不會為它暗自加上一個 this 指標, 也因為缺少 this 指標,static 成員函式無法處理類別之中的 non-static 成員變數。

C++ Object Model

Stroustrup 所設計的 Model:

  • Nonstatic data members 被配置在每一個 class object 之內
  • static data members 被配置在個別的 class object 之外
  • function members 被配置在個別的 class object 之外
  • 每一個 class 產生出指向 virtual functions 的指標,放在表格中(virtual table)。 每一個 class object 都被安插一個指標,指向相關的virtual table。
  • 為了支援 RTTI,會在 virtual table 的第一個 slot 插入型別資訊

多型的實現方式很複雜,大致上是編譯器或 VM 在資料結構內加入一個資料指標,此指標通常稱爲 vptr,是 Virtual Table Pointer 的意思。vptr 指向一個 Virtual Table,此 Virtual Table 是一個陣列 (array),由許多函數指標所組成,每個函數指標各自指向一個函數的地址。不管是 C++ 編譯器、或是 Java VM、或是 .NET CLR,內部都是以此方式來實現多型。

C++ Object Model 提供了有效率的執行時期支援,再加上與 C 之間的相容性,造成了 C++ 的流行。但是因為 Object Layout (物件大小、每一個非虛擬的 member)在編譯時間就已經固定下來,在 binary level 上阻礙了使用的彈性。

C++:封裝(Encapsulation)

資訊隱藏的意義在於將物件的實際內容除非有必要,否則最好將實際內容隱藏在介面裡。

C++ 的存取等級分為 public, protected, private 三種,把資料宣告為 private,只能透過特定的介面來操作,這就是物件導向的封裝(encapsulation)特性。

C++:繼承 (Inherit)

繼承:讓使用者藉由在已經有的類別上,加入新成員(資料或者是函式來定義新的類別,而不必重新設計。

C++ 的繼承分為三種情況:

  • Public
  • Protected
  • Private

成員函式有一個隱藏參數,名為 this 指標(代表著物件自己),因此可以知道所應喚起的函式。

C++ 多型支援:虛擬函式

對物件導向的程式語言來說,在繼承關係發生的同時,子類別可能會去覆寫父類別的函式。因此在所謂「多型」的機制下, 就無法在編譯時期決定要呼叫的究竟是那個函式,也就是到了執行時期才決定要呼叫的究竟是那一個函式(所引申的意義,就是多型的前提是繼承, 只有繼承才有多型行為的產生)。

物件導向的三個特色:封裝、繼承、多型,其中最重要的多型,C++ 是靠繼承和動態繫結(Dynamic binding)達成, 「虛擬函式」可以實現「執行時期」的多型支援,是一個「動態繫結」, 也就是指必須在執行時期才會得知所要調用的物件或其上的公開介面,以相同的指令卻喚起了不同的函式,也就是「一種介面,多種用途」。

如果 C++ 沒有虛擬函式,如果以一個「基礎類別之指標」指向一個「衍生類別之物件」, 那麼使用此指標就只能夠呼叫基礎類別(而不是衍生類別)所定義的函式。C++ 透過指標或參考來支援多型,以 Virtual function 來達到多型的實現, Virtual function 在基底類別中使用關鍵字 virtual 宣告,並在衍生類別中重新定義虛擬函式。 多型與動態繫結只有在使用指標或參考時才得以發揮它們的特性。

虛擬函式可以實現執行時期的「多型」,一個含有虛擬函式的類別被稱為「多型的類別」(Polymorphic class), 當一個基底類別型態的指標指向一個含有虛擬函式的衍生類別,您就可以使用這個指標來存取衍生類別中的虛擬函式。

class Window // Base class for C++ virtual function example
{
  public:
  virtual void Create() // virtual function for C++ virtual function example
  {
    cout <<"Base class Window"<<endl;
  }
};

class CommandButton : public Window
{
  public:
  void Create()
  {
    cout<<"Derived class Command Button - Overridden C++ virtual function"<<endl;
  }
};

void main()
{
  Window  *x, *y;

  x = new Window();
  x->Create();

  y = new CommandButton();
  y->Create();
}

如果沒有宣告為 virtual 的話,CommandButton 所呼叫的 Create() 仍然為 base class 所定義的 Create(),但是宣告為 virtual function 之後,將會視所使用的指標型別而決定要喚起的函式,因此將可以增加使用上的彈性。

純虛擬函式 (Pure Virtual Function)

C++ 提供「純虛擬函式」(Pure virtualfunction),它的存在只是為了在衍生類別中被重新定義,指明某個函式只是提供一個介面, 要求繼承的子類別必須重新定義該函式。

class Work {
  public:
    // pure virtual function
    virtual void doJob() = 0;
};

一個類別中如果含有純虛擬函式,則該類別為一「抽象類別」(Abstract class), 該類別只能被繼承,而不能用來直接生成實例,如果直接產生實例會發生編譯錯誤。

final specifier and override specifier

C++11 標準提供了對虛擬函式更好的表達方式。

final specifier specifies that a virtual function cannot be overridden in a derived class or that a class cannot be inherited from. 如果設定為 final,就表示這就是最後一個覆寫的 virtual function。

struct Base
{
    virtual void foo();
};

struct A : Base
{
    void foo() final; // A::foo is overridden and it is the final override
    void bar() final; // Error: non-virtual function cannot be overridden or be final
};

struct B final : A // struct B is final
{
    void foo() override; // Error: foo cannot be overridden as it's final in A
};

struct C : B // Error: B is final
{
};

override specifier specifies that a virtual function overrides another virtual function. 也就是用來指定是否可以覆寫 virtual function。

struct A
{
    virtual void foo();
    void bar();
};

struct B : A
{
    void foo() const override; // Error: B::foo does not override A::foo
                               // (signature mismatch)
    void foo() override; // OK: B::foo overrides A::foo
    void bar() override; // Error: A::bar is not virtual
};

對於 C++ 而言,因為其設計哲學是「任何特性在不使用的時候,絕對不增加程式的負擔」,所以在不使用虛擬特性的時候,就不會增加呼叫時的負擔。與 Java 這些內建使用動態繫結的語言不同,C++ 比較偏向使用靜態繫結,只有在使用 Virtual 關鍵字時才具有動態繫結的能力,因此與其說 C++ 是一個物件導向語言,不如說是支援物件導向的 Template based 語言。

Templates

Templates are parametrized by one or more template parameters, of three kinds: type template parameters, non-type template parameters, and template template parameters.

C++ 所提供的 template 機制,就是將目標物的資料型別參數化

下面是一個 template 的例子:

template <class T>
inline const T& max(const T& a, const T& b)
{
  return a < b ? b : a;
}

一旦程式以指定引數的方式,確定了型別之後,編譯器便自動針對這個(或這些)型別產生出一份實體。 針對目標物之不同,C++ 支援 function templates 和 class templates 兩大類型, 而後者的 members 又可以是 templates(所謂 member templates),帶來極大的彈性與組合空間。

「由編譯器產生出一份實體」的動作,我們稱之為具現化(instantiation)。由於  Template 具現化的行為是在編譯時期完成,所以愈複雜的 templates,就會需要愈多的編譯時間。然而 template 卻不會影響到執行時間,因此對於程式的執行效率仍然得以保障。

C++ 泛型編程的中心思考是 Template,運算子多載也為 C++ 泛型編程帶來了幫助, 讓我們得以用看起來行為像函式的 Function Object (函式物件, or Functor)寫出更有彈性的程式。 Standard Template Library 是 C++ 泛型編程開花結果之後所帶來的成品,讓我們得以享用這些高編程品質的函式庫。

Templates 是 C++ 支援泛型的重要關鍵。

template<typename To, typename From> To convert(From f);

void g(double d)
{
    int i = convert<int>(d); // calls convert<int,double>(double)
    char c = convert<char>(d); // calls convert<char,double>(double)
    int(*ptr)(float) = convert; // instantiates convert<int, float>(float)
}

關鍵字:typename

C++ 引進了 typename 關鍵字,用來指定 template 內的標識符號為一種型別。 C++ 的規則是,除非用 typename 修飾,template 內的標識符號都會被視為一個實值 (value) 而不是型別。

Parameter pack (since C++11)

A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments.

A template with at least one parameter pack is called a variadic template.

template<class ... Types> struct Tuple {};
Tuple<> t0;           // Types contains no arguments
Tuple<int> t1;        // Types contains one argument: int
Tuple<int, float> t2; // Types contains two arguments: int and float
Tuple<0> error;       // error: 0 is not a type

A variadic function template can be called with any number of function arguments (the template arguments are deduced through template argument deduction):

template<class ... Types> void f(Types ... args);
f();       // OK: args contains no arguments
f(1);      // OK: args contains one argument: int
f(2, 1.0); // OK: args contains two arguments: int and double

A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order.

template<class ...Us> void f(Us... pargs) {}
template<class ...Ts> void g(Ts... args) {
    f(&args...); // “&args...” is a pack expansion
                 // “&args” is its pattern
}
g(1, 0.2, "a"); // Ts... args expand to int E1, double E2, const char* E3
                // &args... expands to &E1, &E2, &E3
                // Us... pargs expand to int* E1, double* E2, const char** E3

Type casting

Type casting is a way to convert a variable from one data type to another data type. For example, if you want to store a 'long' value into a simple integer then you can type cast 'long' to 'int'. You can convert the values from one type to another explicitly using the cast operator as follows −

(type_name) expression

Consider the following example where the cast operator causes the division of one integer variable by another to be performed as a floating-point operation −

#include <stdio.h>

main() {

   int sum = 17, count = 5;
   double mean;

   mean = (double) sum / count;
   printf("Value of mean : %f\n", mean );
}

Type conversions can be implicit which is performed by the compiler automatically, or it can be specified explicitly through the use of the cast operator. It is considered good programming practice to use the cast operator whenever type conversions are necessary.

因為更重視型別安全的關係,除了上面 C 語言風格的型別轉換, C++ 加入了 static_castdynamic_castconst_castreinterpret_cast 四種 cast。

static_cast 執行於編譯時期,功能與 C-Style cast 相似,但更安全,可以避免不合理的型別轉換。

float f = 3.5;
int n1 = static_cast<int>(f);

為了支援執行時期的型態轉換動作,C++ 提供了dynamic_cast 用來將一個基底類別的指標轉型至衍生類別指標, 稱之為「安全向下轉型」(Safe downcasting),它在執行時期進行型態轉換動作,首先會確定轉換目標與來源是否屬同一個類別階層, 接著才真正進行轉換的動作,檢驗動作在執行時期完成,如果是一個指標,則轉換成功時傳回位址,失敗的話會傳回 0, 如果是參考的話,轉換失敗會丟出 bad_cast例外。

#include <iostream> 
#include <typeinfo> 
using namespace std; 

class Base { 
public: 
    virtual void foo() = 0;
}; 

class Derived1 : public Base { 
public: 
    void foo() { 
        cout << "Derived1" << endl; 
    } 
 
    void showOne() {
        cout << "Yes! It's Derived1." << endl;
    }
}; 

class Derived2 : public Base { 
public: 
    void foo() { 
        cout << "Derived2" << endl; 
    } 
 
    void showTwo() {
        cout << "Yes! It's Derived2." << endl;
    }
}; 

void showWho(Base &base) {
    try {
        Derived1 derived1 = dynamic_cast<Derived1&>(base);
        derived1.showOne();
    }
    catch(bad_cast) {
        cout << "bad_cast 轉型失敗" << endl;
    }
}

int main() { 
    Derived1 derived1;
    Derived2 derived2; 

    showWho(derived1);
    showWho(derived2);
 
    return 0;
}

const_cast 的用途是移除 const 的屬性。除非真的有需要,否則不應該使用。

const int a = 10;
const int *ptr = &a;
int *cc = const_cast<int *>(ptr);
*cc = 99;

reinterpret_cast 用途是強制轉換型別,不論資料大小是否相同。

int number = 10;
// Store the address of number in numberPointer
int* numberPointer = &number;

// Reinterpreting the pointer as a char pointer
char* charPointer
    = reinterpret_cast<char*>(numberPointer);

Exception

如果要在 C++ 中實作例外狀況 (exception) 處理,使用 trythrowcatch 運算式。 開發者需要使用 try 包住可能會發生例外的程式碼區段(也就是使用 throw 丟出例外狀況的程式碼), 在 catch 處理這個 try 區域所發生的例外,並且 catch 裡面的 exception 變數應該要用 reference 的方式。 另外,如果在 catch 拿到例外狀況無法即時處理而需要丟給更上層的 try ... catch 處理,可以使用 throw 重新丟出一個例外狀況。

下面是一個例外狀況處理的例子。

#include <iostream>
#include <vector>
#include <exception>

int main()
{
    std::vector<int> v = {1,2,3};
    try {
        std::cout << v.at(0) << std::endl;
        std::cout << v.at(1) << std::endl;
        std::cout << v.at(2) << std::endl;
        std::cout << v.at(3) << std::endl;
    } catch (std::exception &e) {
        std::cout << "exception: " << e.what() << std::endl;
    }

    return 0;
}

C++ 並不支援 finally,因為 C++ 可以使用 RAII(Resource Acquisition Is Initialization), 也就是物件銷毀的時候也關閉或移除其使用的資源。

Namespace

C++ 可以使用 namespace 來定義名稱空間(或者開啟既存的名稱空間),例如,可以在 account.h 中定義 bank 名稱空間:

#include <string>

namespace bank {
    using namespace std; 

    class Account { 
    private:
        string id;  
        string name; 
        double balance;

    public: 
        Account(string id, string name, double balance);
        void deposit(double amount);
        void withdraw(double amount);
        string to_string() const;
    };
}

在使用上,可以在 account.cpp 可以開啟 bank 名稱空間,並在其中實作類別定義:

#include "account.h"

namespace bank {
    using namespace std;

    Account::Account(string id, string name, double balance) {
        this->id = id;
        this->name = name;
        this->balance = balance;
    }

    string Account::to_string() const {
        return string("Account(") + 
            this->id + ", " +
            this->name + ", " +
            std::to_string(this->balance) + ")";
    }
    
    // ...
}

或者是在實作時指定 bank 範疇:

bank::Account::Account(string id, string name, double balance) {
    this->id = id;
    this->name = name;
    this->balance = balance;
}

string bank::Account::to_string() const {
    return string("Account(") + 
           this->id + ", " +
           this->name + ", " +
           std::to_string(this->balance) + ")";
}

名稱空間會是類別名稱的一部份,因此在使用時,必須包含 bank 前置; 或者是使用 using 來指明使用哪個名稱空間,例如:

using namespace std;
using namespace bank;

using 也可用來導入某個名稱,例如僅導入 std::string、std:cout:

#include <iostream>
#include <string>
using std::string;

int main() {
    string str = "Example";
    using std::cout;
    cout << str;
}

C++ 其實並不建議使用 using,因為這樣如果程式碼如果大到一定規模,可能會出現命名衝突的問題。

C++ 11 Lambda Expression

Lambda expression 在 C++ 中可以視為是一種匿名函數的表示方式,它可以讓程式設計師將函數的內容直接以 inline 的方式寫在一般的程式碼之中, 使用時機跟 functor 與 function pointer 類似,一般的狀況都是使用 lambda expression 定義一個匿名的函數, 然後再將此函數當作另外一個函數的傳入參數來使用。

基本的用法如下:
[=] (int x) mutable throw() -> int
{
  // 函數內容
  int n = x + y;
  return n;
}
[=]:lambda-introducer,也稱為 capture clause。
所有的 lambda expression 都是以它來作為開頭,不可以省略,它除了用來作為 lambda expression 開頭的關鍵字之外,也有抓取(capture)變數的功能,指定該如何將目前 scope 範圍之變數抓取至 lambda expression 中使用,而抓取變數的方式則分為傳值(by value)與傳參考(by reference)兩種,跟一般函數參數的傳入方式類似,不過其語法有些不同,以下我們以範例解釋:
  • []:只有兩個中括號,完全不抓取外部的變數。
  • [=]:所有的變數都以傳值(by value)的方式抓取。
  • [&]:所有的變數都以傳參考(by reference)的方式抓取。
  • [x, &y]x 變數使用傳值、y 變數使用傳參考。
  • [=, &y]:除了 y 變數使用傳參考之外,其餘的變數皆使用傳值的方式。
  • [&, x]:除了 x 變數使用傳值之外,其餘的變數皆使用傳參考的方式。

這裡要注意一點,預設的抓取選項(capture-default,亦即 = 或是 &)要放在所有的項目之前,也就是放在第一個位置。

(int x):lambda declarator,也稱為參數清單(parameter list)。
定義此匿名函數的傳入參數列表,基本的用法跟一般函數的傳入參數列表一樣,不過多了一些限制條件:
  • 不可指定參數的預設值。
  • 不可使用可變長度的參數列表。
  • 參數列表不可以包含沒有命名的參數。

參數清單在 lambda expression 中並不是一個必要的項目,如果不需要傳入任何參數的話,可以連同小括號都一起省略。

mutable:mutable specification。
加入此關鍵字可以讓 lambda expression 直接修改以傳值方式抓取進來的外部變數,若不需要此功能,則可以將其省略。
throw():例外狀況規格(exception specification)。
指定該函數會丟出的例外,其使用的方法跟一般函數的例外指定方式相同。如果該函數沒有使用到例外的功能,則可以直接省略掉。
-> int:傳回值型別(return type)。
指定 lambda expression 傳回值的型別,這個範例是指定傳回值型別為整數(int),其他的型別則以此類推。如果 lambda expression 所定義的函數很單純,只有包含一個傳回陳述式(statement)或是根本沒有傳回值的話,這部分就可以直接省略,讓編譯器自行判斷傳回值的型別。
mutable:compound-statement,亦稱為 Lambda 主體(lambda body)。
這個就是匿名函數的內容,就跟一般的函數內容一樣。

下面是一個最簡單的 Hello World 範例。

#include <iostream>

using namespace std;
int main() {
  auto lambda = []() { cout << "Hello, Lambda" << endl; };
  lambda();
}

再來是 Trailing Zero-Bits 的解法:

/*
 * Trailing Zero-Bits
 * Given a positive integer, count the number of trailing zero-bits in its binary
 * representation. For instance, 18 = 10010, so it has 1 trailing zero-bit,
 * and 48 = 110000, so it has 4 trailing zero-bits.
 */
#include <iostream>

int main(void)
{
    int number = 0;

    auto lambda = [](int num) -> int {
        int count = 0;
        while((num & 1) == 0) {
            count++;
            num = num >> 1;
        }

        return count;
    };

    std::cout << "Please input a number: ";
    std::cin >> number;
    if (std::cin.fail()) {
        std::cout << "It is not a number." << std::endl;
        return 1;
    }

    if (number <= 0) {
        std::cout << "Number requires > 0." << std::endl;
    } else {
        std::cout << lambda(number) << std::endl;
    }
    return 0;
}

也可以在參數列加上 void,明確標示沒有傳入參數,並將傳回值的類型設為 void,明確標示這個函數沒有傳回值:

auto lambda = [](void) -> void { cout << "Hello, Lambda" << endl; };
下面的例子是直接呼叫 lambda expression 所定義的匿名函數,將兩個參數傳入其中進行運算,最後再將運算結果傳回來:
#include <iostream>

int main() {
  using namespace std;
  int n = [] (int x, int y) { return x + y; }(5, 4);
  cout << n << endl;
}

C++ 標準程式庫中有許多的函數在使用時會需要其他的函數作為傳入參數,最常見的就是一些對於陣列的處理函數, 這個例子是 std::count_if 最簡單的使用方式:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

bool condition(int value) {
  return (value > 5);
}

int main() {
  vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 };

  auto count = count_if(numbers.begin(), numbers.end(), condition);
  cout << "Count: " << count << endl;
}

這裡我們定義一個 condition 函數,作為 std::count_if 在判斷元素時的依據,std::count_if 會將每個元素一一傳入 condition 函數中檢查, 最後傳回所有符合條件的元素個數。

由於 std::count_if 所使用到的判斷函數都需要另外定義,這樣會讓程式碼顯得很冗長, 我們可以使用 lambda expression 改寫一下,讓整個程式碼更簡潔:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
int main() {
  vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 };

  auto count = count_if(numbers.begin(), numbers.end(),
    [](int x) { return (x > 5); });
  cout << "Count: " << count << endl;
}

我們將原本 condition 函數所在的位置,直接使用一個 lambda expression 替換,至於傳入的參數與傳回值的類型則維持不變(傳入 int,傳回 bool)。

C++ 11 Automatic Type Deduction and decltype

In C++03, you must specify the type of an object when you declare it. Yet in many cases, an object’s declaration includes an initializer. C++11 takes advantage of this, letting you declare objects without specifying their types:
auto x=0; //x has type int because 0 is int
auto c='a'; //char
auto d=0.5; //double
auto national_debt=14400000000000LL;//long long
Automatic type deduction is chiefly useful when the type of the object is verbose or when it’s automatically generated (in templates). Consider:
void func(const vector<int> &vi)
{
    vector<int>::const_iterator ci=vi.begin();
}
而在 C++11,現在可以這樣使用:
auto ci = vi.begin();
C++11 offers a similar mechanism for capturing the type of an object or an expression. The new operator decltype takes an expression and “returns” its type:
const vector<int> vi;
typedef decltype (vi.begin()) CIT;
CIT another_const_iterator;

C++11 也支援了 Range-based for loop,並且支援 auto 的使用,下面是一個九九乘法表的範例:

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> x = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::vector<int> y = {1, 2, 3, 4, 5, 6, 7, 8, 9};

    for (auto& nx: x) {
        for (auto& ny: y) {
            int z = nx * ny;
            std::cout << nx << " x " << ny << " = " << z << std::endl;
        }
    }
}

在 C++14,則可以結合 Lambda Expression 與 auto 的使用,下面是一個範例:

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

int main()
{
  std::vector<int> ivec = { 1, 2, 3, 4};
  std::vector<std::string> svec = { "red",
                                    "green",
                                    "blue" };
  auto adder  = [](auto op1, auto op2){ return op1 + op2; };
  std::cout << "int result : "
            << std::accumulate(ivec.begin(),
                               ivec.end(),
                               0,
                               adder )
            << "\n";
  std::cout << "string result : "
            << std::accumulate(svec.begin(),
                               svec.end(),
                               std::string(""),
                               adder )
            << "\n";
  return 0;
}
下面就是執行的結果:
int result : 10
string result : redgreenblue

IO Stream

C++ comes with libraries that provide us with many ways for performing input and output. In C++ input and output are performed in the form of a sequence of bytes or more commonly known as streams.

  • Input Stream: If the direction of flow of bytes is from the device(for example, Keyboard) to the main memory then this process is called input.
  • Output Stream: If the direction of flow of bytes is opposite, i.e. from main memory to device( display screen ) then this process is called output.

The stream-based input/output library is organized around abstract input/output devices. These abstract devices allow the same code to handle input/output to files, memory streams, or custom adaptor devices that perform arbitrary operations (e.g. compression) on the fly.

Most of the classes are templated, so they can be adapted to any basic character type. Separate typedefs are provided for the most common basic character types (char and wchar_t).

C++ 提供了 stream 的方式來看待輸出與輸入。下面的範例是讓使用者輸入 A 與 B 以後,輸出相加的數字:

#include <iostream>

int main()
{
    int a = 0, b = 0;

    std::cout << "Please input the name a: ";
    std::cin >> a;

    std::cout << "Please input the name b: ";
    std::cin >> b;

    std::cout << "The sum is " << a+b << "." << std::endl;
}

下面是從 /etc/os-release 讀取內容,然後取得 Linux Distribution Name 的範例:

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

#ifdef _WIN32
   #include <io.h>
   #define access    _access_s
#else
   #include <unistd.h>
#endif

#ifdef ENABLE_STD
   #include <filesystem>
#endif

using namespace std;

/*
 * Using access function to check file exist or not
 */
bool FileExists( const string &Filename )
{
    return access( Filename.c_str(), 0 ) == 0;
}

/*
 * Split incoming string and return a vector
 */
vector<string> split(const string& str, const string& delim)
{
    vector<string> tokens;
    size_t prev = 0, pos = 0;
    do
    {
        pos = str.find(delim, prev);
        if (pos == string::npos) pos = str.length();
        string token = str.substr(prev, pos-prev);
        if (!token.empty()) tokens.push_back(token);
        prev = pos + delim.length();
    } while (pos < str.length() && prev < str.length());

    return tokens;
}

/*
 * get Linux distributed name: use /etc/os-release file
 */
string getListributedName()
{
    string name = "";

#ifdef ENABLE_STD
    std::filesystem::path p("/etc/os-release");
    if(std::filesystem::exists(p)) {
#else
    if(FileExists("/etc/os-release")==true) {
#endif
        ifstream releasefile("/etc/os-release");
        string line;

        if (releasefile.is_open()) {
            while ( getline (releasefile, line) )
            {
                auto splitArray = split(line, "=");

                if(splitArray[0].compare("NAME")==0) {
                   name =  splitArray[1];
                   break;
                }
            }

            releasefile.close();
       }
    }

    return name;
}


int main(int argc, char *argv[])
{
    string name = getListributedName();
    std::cout << name << std::endl;
}

C++17 加入了 Filesystem library,提供了對於 files 與 directories 的操作。

編譯:
g++ getDistributionName.cpp -std=c++17 -o getDistributionName

如果要配合 C++ standard library:
g++ getDistributionName.cpp -std=c++17 -o getDistributionName -DENABLE_STD

參考資料

2024/12/20

戰神:狂神天威3

《戰神:狂神天威3》(Warlords Battlecry III,也有翻譯為《呼嘯戰神3》)是由 Infinite Interactive 開發並於 2004 年發行的即時戰略遊戲, 共有16 個種族,28 種職業,為《戰神:狂神天威》系列的第三部作品。《戰神:狂神天威》系列以首創將角色扮演要素融入即時戰略而聞名, 導入了英雄和昇級系統,藉由戰鬥提升經驗值,學習魔法和技能,特點在於英雄的等級與技能會在戰役後持續保留, 並且有隨從 (Retinue) 的設計。GOG 有販售此遊戲, 已更新到 patch 1.03。Steam 也有販售此遊戲, 不過採用的是 unofficial patch。

(注意: Unofficial patch 1.03.24 與 1.03.25 分別由不同的團隊修改與維護!因此需要將二者的討論分開。)

可以參考的資料:

Overview

在單人遊戲方面,可以分為 Campaign(在 Etheria 世界的劇情故事) 以及對抗電腦對手的 Skirmish。同時也有 Tutorial 關卡,使用 Dwarf 進行教學。
在成功的達成結局之後,玩家仍然可以在 Campaign 的地圖繼續遊玩與執行任務,同時在這個界面整理自己的裝備。 不管是什麼理由,如果想重玩,可以使用遊戲提供的 Reset Campaign 來達到這個目的。

由於英雄的等級與技能會在戰役後持續保留,因此在等級不同的情況下會有不公平或者是平衡的問題。 遊戲提供了 Freeze your hero's level 的選項,在進行多人連線時通常會講好英雄的等級(例如 50 級的英雄), 在相同等級的情況下競技。

三代故事建立在 Dark Elf 嘗試召喚 Daemon Lord,而因為如此有 Four Horsemen 進入 Etheria 世界。 其中代表瘟疫的 Lord Antharg 創造了 Plaguelord,代表戰爭的 Lord Sartek 創造了 Minotaur, 代表饑荒的 Lord Melkor 創造了 The Swarm,代表死亡的 Lord Bane 創造了 Undead。 其中 Minotaur 為 Neutral alignment,其餘三者為 Evil alignment。 Campaign 劇情故事就是主角發現有第五個 Daemon Lord、也就是代表毀減的 Lord Gorgon 進入這個世界, 主角走遍 Etheria 世界,在知道 Lord Gorgon 無法被毀滅以後,最後封印 Fifth Horseman 的故事。

在 Campaign 中,有七個地方完成任務以後可以僱用一些助力成為英雄隨從 (Retinue) , 包含 Ragnar's Pass 的 Ragnar (the Frost Dragon), Theira 完成 Troll Hunt 任務(並且有機會成為 Knight 的盟友)以後,可以僱用 Prince Henrik (Knight); Daros 完成 Barbarian 的挑戰任務以後可以僱用 Warlord, Twilight Woods 幫助 Fey 以後可以僱用 Unicorn, 在完成護送 High Elf 的 Queen 到 Lurarion 的任務以後可以僱用 Moonguard, 在完成 Hand of Sartek Bonus 以後可以在 Realms of War 僱用 Minotaur King, 以及在 White Mountains 如果是 Dwarf 的友好方或者是完成 Griffon Raid 的任務取得 Griffon Eggs Bonus 以後可以僱用 Griffon (注意: White Mountains 任務會降低 Dwarf 對你的 diplomatic scores,即使是 Dwarf 英雄也會下降)。 而 Siria 的 Temple of Sirian 可以僱用 Archon,以及在 Elenia 可以僱用 Squire

在 Campaign 中有幾個地方是可以使用錢(遊戲中稱為 Crowns)來換取一些英雄的經驗值,包含完成任務以後的 Twilight Woods 與 Lurarion, 以及 Siria。

遊戲中使用下列四種資源,每個種族各有其偏重使用的資源:
Gold, Metal, Stone 和 Crystal

《戰神:狂神天威》系列採用 5 級科技樹,主堡最高為第 5 級。如果地圖沒有特別設定,各種族的主堡都具有轉化 (Convert) 的能力。 和一般遊戲不同,玩家需要使用英雄或者是具有轉化 (Convert) 能力的單位轉化資源為己方的資源,而後才開始有收入。

一般而言,等級愈高的主堡就會提供愈高的 Army Limit, 而 Army Limit 也可以透過建造建築而增加(通常是 +2,但是也有 +1、+3 與 +4 的建築)。 而有些種族則對於 Army Limit 有額外的支援。Empire 可以在 Granary 研發 Supply(共有 4 級,效果是 +5, +10, +15, +20)。 Barbarian 可以在 Chieftain's Hut 研發 Horde(共有 9 級,效果是 +5, +10, +15, +20, +25, +30, +35, +40, +50)。 Dark Dwarf 可以建造 Supply Depot 來 +3 Army Limit。 Orc 可以建造 Hovel 來 +3 Army Limit。

英雄具有轉化 (Convert) 以及建造主要建築的能力。 在一開始的時候玩家需要轉化資源以及建立主堡,因此除非是在劇情中 No buildings 的角色扮演模式, 否則在遊戲戰役一開始選擇需要攜帶的人員時,就需要攜帶一些工人或者是 builders 才行。

而能夠建造所有建築的工人 builder 是否生產自主堡,則是各個種族有其不同的設計。 舉例來說,EmpireKnight 有共同的工人 Peasant,BarbarianMinotaur 有共同的工人 Thrall, Fey 的工人為 Oakman,Orc 的工人為 Kobold,Daemon 的工人為 Quasit, High ElfWood ElfDark Elf 的工人為 Wisp,都是生產自主堡, 差別在於三個 Elf 種族其工人 Wisp 無法進入礦產挖礦加快資源的收入,而其它種族的工人可以。 而 Dwarf 的工人 Smith,Ssrathi 的工人 Chameleon,Dark Dwarf 的工人 Engineer, The Swarm 的工人 Giant Ant,PlaguelordUndead 的工人 Zombie 則並非生產自主堡。

Tower 是每個種族用來鞏固基地或地圖上某個位置的主要防禦工事。英雄無法建造 Tower,因此必須由工人或者是 builders 建造。 Tower 可以在其中駐紮 (garrison) 一些單位。但並非所有單位都能駐紮。 在可以駐紮的單位中,普通步兵可以分別增加塔樓 3 點戰鬥力和 1 點攻擊速度。一個英雄相當於兩個普通單位。 如果你駐紮一個遠程攻擊單位,塔樓的傷害力將增加 10 點,射程將增加 1 點。 你可以根據需要混合使用遠程單位和近戰步兵來獲得所需的屬性。 作為獎勵,駐紮的英雄擁有雙倍 health regeneration,所以這是快速恢復生命值低的英雄的一種方法。

整個遊戲的戰鬥可以區分為近戰 (melee) 和遠程 (ranged) 二種類型。 Combat 是遊戲中兩個或多個單位進行近戰時所使用的主要屬性,也是整個戰鬥系統的第一步。 Combat 用於確定一個單位的攻擊是否能夠命中、輕微命中、致命一擊、造成致命一擊或未命中另一個單位。

在遊戲中的 Speed 可以分為二種,一種是移動速度 (Movement Speed),一種是攻擊速度 (Attack Speed)。 移動速與各個單位的 Speed 屬性數值有關;英雄的攻擊速度與他們的 dexterity 數值有關, 而如果不是英雄,那麼攻擊速度與士氣 (Morale) 有關。

遊戲中物理傷害類型有三種,PiercingCrushingSlashing,而其中 Slashing 是最常見的類別(主要與劍和斧頭有關)。 元素傷害類型有三種,FireColdElectric。 最後,還有不是物理傷害與元素傷害類型的 Magic 類型,是一種獨特的類型。 Armor 可以降低來自物理傷害類型 (Piercing, Slashing and Crushing) 與 Resistance 可以降低來自 元素傷害類型 (Fire, Cold and Electric) 的傷害,Magic Resistance 則是降低 Magic 類型的部份。

在遊戲中有二種疾病 (Illnesses)和四種被稱為精神效果 (psyche effects) 的狀態,這些都使用相同的機制, 因此一個單位在同一時間不能擁有超過一種精神效果或超過一種疾病。但是,一個單位可以同時擁有一種精神效果和一種疾病。 二種疾病分別為 PoisonDisease,如果在這個狀態下會防止 HP regeneration 並且緩慢的扣除生命值。 四種精神效果的狀態分別為 Fear, Terror, ChaosAwe

遊戲中有態度 (Attitude) 的設計,可以決定單位在戰鬥和地圖上的行為和 AI 設定。 這些不同的態度 (Attitude) 允許玩家控制單一單位的行動,例如它們是否自動施法、守衛或追擊敵人。 舉例來說,可以設定一些單位的態度為 Guardian 或者是 Magic Guardian,用來守護其它的單位(例如英雄), 或者將法師設定為 Magic Defender,讓法師在一些情況下會使用法術。

每個種族都有設計其將軍 (general),通常在第五級主堡的時候可以生產(有例外的例子,White Mage 在第四級主堡就可以生產), 為各個種族具有轉化 (Convert) 能力的單位, 包含 Dwarf Lord (Dwarf), White Mage, Red Mage, Black Mage (Empire), Moonguard (High Elf), Inquisitor (Knight), Reaver (Barbarian), Banshee (Fey), Minotaur King (Minotaur), Naga (Ssrathi), Dryad (Wood Elf), Summoner (Daemon), Blackguard (Dark Elf), Bronze Golem (Dark Dwarf), Giant (Orc), Plague Priest (Plaguelord), Scorpionpriestc (The Swarm), Vampire (Undead)。

在一些地圖有所謂的 Temple(Celestial Temple, Elemental Temple, Infernal Temple 或者是 Snake Temple), 當己方的單位轉化 (Convert) Temple 為己方的建築以後,可以自 Temple 生產單位,包含 Archon, Water Elemental, Air Elemental, Fire Elemental, and Earth Elemental, Daemon 或者是 Naga。

另外,遊戲還有終極單位 Titan 的設計, Titan 是可以與高等級英雄旗鼓相當的作戰單位,每場戰役只能夠生產一位, 在第五級主堡並且達成條件的時候可以生產,每個種族都有自己獨特的 Titan 單位。

Races

可玩的種族有 16 種:

  • Dwarf
  • Empire
  • High Elf
  • Knight
  • Barbarian
  • Fey
  • Minotaur
  • Ssrathi
  • Wood Elf
  • Daemon
  • Dark Elf
  • Dark Dwarf
  • Orc
  • Plaguelord
  • The Swarm
  • Undead

Dwarf 是 Tutorial 關卡使用的種族。Drawf 在初期需要建設其經濟(因為其價格較貴的單位, 而升級與單位生產大多數都需要 Gold),同時其大多數的單位移動速度較慢,因此 Dwarf 在初期是處於劣勢的。 還有要注意的是,Dwarf 沒有騎兵單位。 Dwarf 主堡 Citadel 並不生產工人,而是由 Foundry 生產 Smith。Smith 如果進入礦產挖礦,會被計算為放入 2 個工人。 Dwarf 除了 Tower,還有主堡升到第三級以後可以建造對地的炮塔 Mortar。 Dwarf Runner 可以研發 Palace MessengerRoyal Messenger 增加移動速度, 同時有不錯的 missile resistance,不過需要研發 WeaponsmithArmorer 才比較好用。 Dwarf Infantry 是 Dwarf 的初階步兵,其價格偏高,主要使用 Metal 生產,對於 Elf 有攻擊加成。 Dwarf Berserker 有較高的物理傷害抗性,同時是對於騎兵有攻擊加成的兵種。Khazrimi Guard 則是對於元素攻擊有不錯的 resistance。 另外弓箭手 Dwarf Crossbow 的價格偏貴不過還可以使用。 Runelord 是 Dwarf 的法師,提供攻擊火力並且可以使用 Doomstones 與 Stonecall 二種法術,是強大的單位。 Ballista 是 Dwarf 的攻城單位,主要用途是用來對抗步兵,當對抗使用大量生產的種族時,可以生產 1 到 2 隻作為輔助。 Dwarf Lord 是 Dwarf 的將軍,移動速度緩慢,一般而言需要有轉化 (Convert) 能力的單位時才需要生產,另外可以作為吸引火力使用。 Dwarf 的初階飛行單位 Eagle 具有建造建築的能力。 Griffon 是 Dwarf 的高階飛行單位,雖然沒有什麼特別的能力,不過可以對空對地,加上其不錯的移動速度,是十分好用的輔助兵種。 因為 Dwarf 升級時使用較多的 Gold 與 Stone,所以可以嘗試使用有 Wealth 技能的英雄職業加強經濟方面, 例如 Merchant, Bard 或者是 Assassin。 要注意的是 Dragonslayer 在 unofficial patch 被移除了 Wealth 技能, 所以在 1.03 是個選擇但是在 unofficial patch 不是。 雖然缺乏 mana regeneration 研發的支援,不過因為 Rune Magic 是 Dwarf 英雄的種族技能, lv5 的技能 Runic Lore 可以加強法師 Runelord,所以可以嘗試 Runemaster 這個職業。 還可以嘗試的法師類英雄是 Healer,雖然無法幫助 Dwarf 的經濟,但是補足沒有醫療的部份。 如果想要嘗試輔助類的英雄,可以使用具有 Running 技能的 Thief 或者是 Ranger。 英雄職業也可以嘗試 Tinker,雖然技能並不完全符合 Dwarf 的需要,Alchemy 的法術(例如 Acquire)仍然可以提供一定的幫助。

二代的 Human 在三代分裂為二個陣營,EmpireKnight

Empire 是一個全面的種族,具有對騎兵有攻擊加成的初階步兵 Pikeman,普通但是也沒有特別弱勢的弓箭手 Archer, 三種法師 (White Mage, Red Mage, Black Mage),只要有錢就能很快生產的騎兵 Mercenary, 以及新的騎兵兵種 Elephant,並且高階步兵 Halberdier 一樣對騎兵有攻擊加成。 Catapult 與 Battering Ram 則是 Empire 的攻城武器。 Pikeman 與 Halberdier 這二者的差別主要在物理傷害類型不同,Pikeman 使用 Piercing,而 Halberdier 使用 Slashing。 White Mage, Red Mage, Black Mage 為 Empire 的將軍,也是 Empire 的特別之處,擁有一種以上的將軍單位。 White Mage 的攻擊類型為 Electric,Red Mage 的攻擊類型為 Fire,Black Mage 的攻擊類型為 Cold。 White Mage 是十分有用的輔助單位,除了轉化 (Convert) 能力還具有 Cure 以及 Group Healing 技能。 Empire 的初階飛行單位 Eagle 具有建造建築的能力。Griffon 是 Empire 的高階飛行單位。 Palace GuardRoyal GuardImperial Guard 是用來加強 Pikeman 與 Halberdier 的研發項目。 MysticismAdvanced Mysticism 是法師相關的研發,在 Library 開發,都可以 Mana 最大值增加 15。 Empire 有個要注意的點,如果要生產騎兵單位 Mercenary, 最好先在三級主堡才能夠建造的 Archway 研發 Fame 降低其生產成本以後再生產。 Empire 在 Quartermaster 的研發 Foreign Mercenary 有趣的點是僱用的傭兵是隨機的,也就是玩家無法知道會出現什麼助力。 因為有 White Mage 可以醫療的關係,所以可以嘗試戰士類的英雄職業,例如 Warrior。 雖然 Empire 的英雄種族天賦有 Wealth,但 Empire 在建造或者是升級 Palace 時,除了最高等級並非以 Gold 而是使用 Metal 為主要使用資源, 因此只有以 Mercenary 作為主力時才需要大量的 Gold,在這個情況下擁有 Wealth 技能的 Merchant, Bard 以及 Assassin 都可以列入選擇。 如果想試著使用法師類的英雄,可以考慮 Sage,因為其 Mage King 技能可以用來加強 White Mage, Red Mage, Black Mage。 也可以考慮使用 Pyromancer,Pyromancy 的法術中使用 Soul Flame 法術增加作戰單位 XP, 以及使用 Cauterize 補血,並且使用法術攻擊敵人。另外,因為 Empire 種族英雄技能的法術系列為 Alchemy, 還可以考慮的法師職業為 Alchemist。如果想要使用直接攻擊敵人的法術,可以考慮使用 Chaos Magic 法術的 Shaman, 雖然前面學習的法術效果都是隨機的,但是 Wildfire 與 Chaos Plague 是強力的攻擊法術。 也可以考慮的法師職業為使用 Ice Magic 法術的 Ice Mage,Ice Magic 也是偏向攻擊方向的法術系列 (但是注意 Empire 沒有 mana regeneration 研發的支援)。

Knight 繼承了二代的騎兵體系(Knight, Knight Champion, Knight Lord), 加上初階步兵 Swordsman,可對空對地的單位 Dancing Sword, 價格偏貴但是有 Cure 技能的飛行單位 Archon 與有 Purify 技能的法師 Inquisitor (Inquisitor 也是 Knight 的將軍,具有轉化的能力)。 Knight 的 弓箭手 Squire 雖然價格不算貴而且生產的速度不慢,不過相較於其它種族的弓箭手而言是偏弱的, 所以如果要對抗較大量的空軍,一般而言在可以生產 Dancing Sword 以後會考慮使用更多的 Dancing Sword 配合而不是單純使用 Squire。 Knight 的初階飛行單位為 Eagle,具有建造建築的能力。Knight 的高階飛行單位為 Pegasus。 Crusade 是一項有趣的研發(共有五級),研發後作戰單位如果殺掉敵人,可以取得額外的 XP。 因為 Knight 是以 Gold 為中心的經濟,所以英雄技能一樣有 Divination Magic 同時又有 Wealth 技能的 Bard 是不錯的選擇 (Bard 可以使用 Divination Magic 中的 Telepathy 增加新產出的單位 XP, Mind Leech 偷取敵人的 XP 以及使用 Comprehension 降低研發的成本, Call Sage 則是可以召喚 Black, Red 或者 White Mage 其中一種法師), 再來是具有 Wealth 技能的英雄。 如果想要偏向戰士類的,可以考慮 Paladin(因為其 Healing Magic 與 Knight Protector 技能), 以及 Warrior(因為與 Knight 種族技能相合)。 如果是法師,可以考慮 Priest 或者是 Healer, 另外因為種族英雄的法術為 Divination,也可以考慮 Sage(但是注意 Knight 沒有 mana regeneration 研發的支援)。

High Elf, Wood ElfDark Elf 分別是代表 Elf 中 Good alignment, Neutral alignment 與 Evil alignment 的種族,都是擁有優秀弓箭手與法師的種族, 並且需要在主堡研發相關 Rune 的科技才能夠生產相關的兵種。 三個種族的工人 Wisp 無法進入礦產挖礦加快資源的收入, 而是需要在二級主堡研發 Ancient Wisp,而後 4 個 Wisp 合成一個 Ancient Wisp 增加 Crystal 的收入, 也因此 Elf 三個種族都需要在資源管理上耗費心力。三個種族的初階飛行兵種 Phoenix 具有轉化 (Convert) 的能力,善用這一點可以取得一些優勢。 注意三個 Elf 種族英雄技能都有增加 Mana 的 Lore 技能,而只有 Dark Elf 有 Summon Mana 研發。

High Elf 是一個強大的種族。 Iceguard 是 High Elf 的初階步兵,除了生命值略低,其它數值相比其它種族的初階步兵算是不錯的作戰單位。 Longbow 是 High Elf 的弓箭手,在研發 Rune of Cielos 之後可以生產,研發項目則在 Shooting Range。 Dragon Knight 是 High Elf 的騎兵,可以對空對地,在升到二級主堡後,研發 Rune of Animos 後可以生產。 Unicorn 在研發 Rune of VivosRune of Animos 之後可以生產,是具有醫療能力的騎兵單位,可以作為輔助單位使用。 Mystic 與 Ice Maiden 為 High Elf 的法師,Mystic 的攻擊距離較短,可以施展 Ring of Ice 和 White Ward; Ice Maiden 的攻擊距離長,可以施展 Hand of Ice 和 Freeze。 三個 Elf 種族中只有 High Elf 有攻城單位,可以用來對抗步兵的 Manticore。 Pegasus 是 High Elf 的高階飛行單位,而且 High Elf 還有生產於 Dragonstone、同樣也是高階飛行單位的 Wyvern。 Moonguard 是 High Elf 的將軍同時也是優秀的遠程攻擊單位,除了轉化 (Convert) 能力還具有 Multi-target 技能。 因為 High Elf 種族英雄技能有 Healing Magic 法術,有 Elcor's Balm 與提升 health regeneration rate 的研發 Healing, 以及 Unicorn 提供醫療,所以可以嘗試戰士類的英雄職業,例如 Warrior。 如果想嘗試法師類的英雄,因為種族英雄的法術為 Healing Magic,可以考慮 Priest 或者是 Healer; 而因為其種族英雄法術的關係,也可以考慮 Paladin(但是注意 Knight Protector 技能對於 High Elf 騎兵沒有幫助,所以可以不用學習)。 如果想要使用提供資源的英雄,因為 High Elf 在研發升級時略為偏重使用 Crystal,可以嘗試使用有 Gemcutting 技能的 Merchant 或者是 Ice Mage。

Wood Elf 是一個初期弱勢同時需要良好建設經濟的種族,英雄隨從中帶一個 Ancient Wisp 是一個不錯的主意。 Forestguard 是 Wood Elf 的初階步兵,相比於其它種族的初階步兵而言比較弱小,沒有特別優秀的地方。 Gladewarden 是 Wood Elf 的弓箭手,在研發 Rune of Cielos 之後可以生產,研發項目則在 Rangers' Guild。 Woodrider 是 Wood Elf 的初階騎兵,在升到二級主堡後,研發 Rune of Animos 後可以生產。 Elven Hunter 是 Wood Elf 的高階騎兵,Rune of CielosRune of Animos 二者都有研發就可以生產, FletcherBowyerFlaming Arrows 對於 Elven Hunter 也有效用。 Druid 是 Wood Elf 的法師,在升到三級主堡後,研發研發 Rune of Manos 後可以生產,具有施展 Call Lightning 法術的能力。 Treant 是 Wood Elf 的高階步兵,在升到四級主堡後,Rune of CielosRune of Arbos 二者都有研發就可以生產, 可以建造主要建築,是高效率的 builder,同時有 Entangle 能力可以降低敵人的速度。 Ancient Treant 是高階的步兵,有 Entangle 能力可以降低敵人的速度,死亡時可以分裂為 2 個 Treants,但是沒有建造主要建築的能力。 Dryad 是 Wood Elf 的將軍,相比於其它種族的將軍而言比較弱,優點是轉化 (Convert) 的速度比其它將軍快 25%。 Griffon 是 Wood Elf 的高階飛行單位,因為 Wood Elf 的種族英雄技能中有 Sky Rune,所以 Griffon 這個飛行兵種也有所獲益。 Rune of Arbos 在研發後可以讓 Gladewarden +2 missile range 並且給予額外的 +5 damage, 同時給予 Elven Hunter +2 combat。 Wood Elf 在第四級主堡的時候可以建造 Magic Well 增加 Gold 收入。 White Tree 則是用來生產 Sprite 與 Pixie,以及 Treant 相關的研發。 對於 Wood Elf 來說,還有個劣勢是 Tower 以其價格來說偏貴但是卻沒有其它種族的 Tower 強。 Forest Tower 則是可以用來對空的偵察塔。 以英雄選擇來說,因為 Wood Elf 有 Elcor's Balm 與提升 health regeneration rate 的研發 Healing, 可以嘗試戰士類的英雄職業,例如 Warrior 或者是 Daemonslayer;Daemonslayer 使用 Summoning Magic, 因此可以使用 Summon Quasit 並且讓 Quasit 進入礦產挖礦稍微改善經濟情況以及使用 Phantom Steed 在戰鬥的時候加強騎兵。 也可以考慮同樣有 Nature Magic 技能的 Druid 或者是 Ranger,Druid 的技能 Guardian Oak 可以用來加強 Treant, Ranger 的技能 Griffonmaster 可以用來加強 Griffon。 如果想要使用提供資源的英雄,因為資源方面偏重使用 Crystal,可以嘗試使用有 Gemcutting 技能的 Merchant 或者是 Ice Mage。

Dark Elf 有豐富的兵種。 Dark Infantry 是 Dark Elf 的初階步兵,並沒有研發可以特別加強這個兵種,但是對於 Dwarf 有攻擊加成。 Dark Archer 是 Dark Elf 的弓箭手,攻擊具有 Poison 傷害,在研發 Rune of Cielos 之後可以生產,研發項目則在 Gallery。 Dark Rider 是 Dark Elf 的騎兵,在升到二級主堡後,研發 Rune of Animos 後可以生產,對於英雄有攻擊加成。 生產自 Tomb 的 Skeleton 擁有不錯的 missile resistance,Spider 與 Queen Spider 則都有 Poison 能力。 Sorceror 是很優秀的法師單位,在升到三級主堡後,研發研發 Rune of Manos 後可以生產, 具有強大的攻擊法術(Pillar of Fire, Darkstorm),還可以召喚 Zombie 並且讓他們進入資源挖礦。 Spider Priestess 也是 Dark Elf 的法師單位,攻擊距離比 Sorceror 短,不過有可以召喚一群 Queen Spider 的能力。 在第四級主堡研發 Rune of Mortos 以後可以生產 Assassin,Assassin 擁有 Assassination 與 Poison 能力, 相關的研發則在 Reformatory 研發 Dark Order 可以 +3% assassination chance, 而 Blood Potion 也可以 +3% assassination chance。 Blackguard 是 Dark Elf 的將軍,除了轉化 (Convert) 能力還具有 Invisibility 能力,可以用來作為間諜或者是打了就跑戰術使用。 Sorcery 是在 Void 的研發項目,共有 2 級,每級可以 Sorceror 的 Mana 最大值增加 15。 Darkbolt 則是用來增加 Sorceror 與 Spider Priestess 的攻擊,研發後可以 +15 ranged damage。 Black Ward 這項在 Tomb 的研發項目可以增加英雄與所有單位 +3, +6 與 +9 resistance。 Burial 在研發後可以建造 Gravestone 這個用來生產 Skeleton 的建築。 Harpy 是 Dark Elf 的高階飛行單位,有 Poison 能力並且可以施展 Drain Mana 技能,但是只能對地。 Harpy Hag 是 Harpy 的研發技能,可以給予 +3 combat。 Imp 是生產自 Kargothian Gate 的飛行單位。 Dark Elf 種族英雄技能在 lv10 為 Death Rune(用來增強 Assassin 這個兵種)與 lv30 為 Assassin,所以適合 Dark Elf 的英雄為 Assassin。 因為 Dark Elf 研發中有 Summon Mana,加上其種族英雄技能有 Summoning Magic, 也可以考慮選擇 Summoner 或者是 Daemonslayer。 如果想嘗試不同的英雄,可以考慮有多種法術的 Archmage(需要高等級才能發揮潛力的英雄,很難用好的進階英雄), 或者是各種法師類的英雄職業。 如果想要使用提供資源的英雄,因為資源方面偏重使用 Crystal,可以嘗試使用有 Gemcutting 技能的 Merchant 或者是 Ice Mage。

Fey 是二代新增的種族,缺少攻城武器單位,在一開始的時候因為單位較為弱小, 是需要資源升級單位並且度過初期弱勢的種族(同時需要累積更多戰鬥單位,是適合大量生產的種族), 建築的體積小,Unicorn 作為騎兵單位具有醫療能力,可以對空對地的 Leprechaun 還可以增加 Gold 的收入。 Orb of Wonder 雖然只有一種研發項目 Lore (levels 1 - 9),不過對於 Fey 而言是重要的建築,最好建造多個並且能夠研發升級就研發。 Rainbow 這個二級主堡才能建造的建築可以用來生產 Leprechaun 並且研發 Income (levels 1 - 4), 如果以大量的 Leprechaun 作為主力,那麼 Rainbow 也是一個重要的建築。 Lightning Hawk 是 Fey 的初階飛行單位,雖然只能對地,但是攻擊類型為 Electric。 Pegasus 是 Fey 的高階飛行單位。Banshee 是 Fey 的將軍,除了轉化 (Convert) 能力還可以造成敵人 Fear,是優秀的支援單位。 The Alicorn 這項研發可以帶給 Unicorn +10 melee damage。 Fey 的 Crystal Tower 有個特別的地方是如果殺死敵人的單位會得到 85 Crystal。 一般而言,英雄應該選擇 Merchant 來取得生產折扣以及更多的資源,因為高等級的 Merchant 有 Gemcutting 技能; 還可以的選擇是也有 Gemcutting 技能的 Ice Mage。 Fey 的種族英雄技能中有 Illusion Magic,所以可以考慮 Illusionist 或者是 Thief。 因為 Unicorn 具有醫療能力,所以可以嘗試戰士類的英雄職業,例如 Warrior。 在 unofficial patch 中 Fey 的種族英雄技能有被修改,增加了 Gemcutting 刪除了 Energy, 這個改法對於工人 Wisp 無法進入礦產挖礦加快資源的收入的三個 Elf 種族來說是破壞平衡的改法。

BarbarianMinotaur 二個種族能夠生產的種類較少,二個種族的工人 Thrall 還是整個遊戲中建造效率最差的工人。

Barbarian, Minotaur, Orc 這三個種族都有掠奪敵人資源的方式。 Barbarian 如果摧毀敵人的建築可以取得 100 Gold; Minotaur 如果摧毀敵人的建築可以取得 100 Metal,Basilisk 每殺死一個敵人就可以拿到 50 Stone, Gnoll 如果 Assassination 技能暗殺敵人成功可以拿到 100 Gold(在 1.03 patch 的數值); Orc 如果摧毀敵人的建築可以取得 100 Stone。 另外,三族都有 Training 這項研發,可以在 Barbarian 的 Camp, Minotaur 的 Arena 與 Orc 的 Battleyard 中研發此項目, 研發後新生產的單位都會 +10 XP,不過不會影響之前都已經存在的部隊,所以愈快研發愈好。

Barbarian 缺少攻城武器以及法師。 優點是經濟均衡,單位生產資源主要是使用 Metal (Barbarian, Rider) 和 Stone (War Dog), 生產速度不慢。在 Fortress 的研發項目 Hunting 最好儘快研發,對於 Barbarian 這個兵種有很大的幫助。 Warlord 是 Barbarian 這個種族在三代新增的高階騎兵,花費並不貴,相比其它的 Barbarian 單位有較高的 Armor,是很有用的單位。 Reaver 是 Barbarian 的將軍,只能用來對地,不過移動速度快,對於大型的敵人有攻擊加成。 Barbarian 的 Summon Mana 是在 Altar of Tempest 研發, 而 Altar of Tempest 還可以生產 Lightning Hawk,雖然只能對地,卻是 Barbarian 的單位中少數具有不同攻擊類型的單位。 Eagle 是 Barbarian 的初階飛行單位,只能對空,但是具有建造所有建築的能力。 Pegasus 是 Barbarian 的高階飛行單位,移動速度快,可以對空對地,可以用來輔助對抗其它種族的空軍。 Scout Tower 是 Barbarian 可以用來對空對地的偵察塔。 Chieftain 是為了加強 Barbarian 的優點而出現的英雄(Barbarian King 技能用來加強 Barbarian, Rider 與 Warlord), 在 unofficial patch 將 Barbarian King 改為 Riding,也就是只加強騎兵(與二代的 Barbarian class 相同), 在 Barbarian 缺少醫療手段的情況下,Barbarian 缺少良好的戰士型英雄支援,所以改弱 Chieftain 是錯誤的修改方向。 其它的英雄選擇是啟用法師類的英雄,因為 Barbarian 有 mana regeneration 研發的支援, 所以使用英雄作為法術輸出以及補強弱點的部份是可行的方向,如果考慮 Barbarian 沒有醫療的方式,可以考慮 Healer。 雖然 Barbarian 的種族英雄技能中有 Ice Magic,但是 Ice Magic 大多數為攻擊法術的法術系列, Ice Mage 並不完全適合 Barbarian(可以用但不夠好)。如果想要嘗試輔助類的英雄,可以使用具有 Running 技能的 Thief。 如果想要使用提供資源的英雄,可以考慮 Tinker 或者是因為 Barbarian 的種族技能有 Quarrying,所以使用有 Smelting 技能的 Daemonslayer。

Minotaur 缺少騎兵單位,單位強壯可靠但是造價較為昂貴, 不過 Minotaur 可以生產 Sheep 以及食用無害動物讓 Minotaur 英雄以及單位 (Minotaur, Axe Thrower, Minotaur Shaman, Minotaur King)自我醫療。 Minotaur 是 Minotaur 的初階步兵,研發升級以後在戰役後期仍然是不錯的單位。 Axe Thrower 是 Minotaur 的初階遠程攻擊單位,只是攻擊距離不長,但是攻擊可以穿過多個敵人。 Gnoll 是 Minotaur 的高階步兵,比起其它兵種數值並不是十分出色,不過具有 Assassination 能力。 Minotaur King 是 Minotaur 的將軍,除了轉化 (Convert) 能力還可以造成敵人 Fear,並且還有 Ignores armor 技能。 Basilisk 提供了加快收集 Stone 的方式(每殺死一個敵人就可以拿到 50 Stone),是很有用的單位。 Bat 是 Minotaur 的初階飛行單位,只能用來對空,是適合用來偵查的兵種。 Griffon 是 Minotaur 的高階飛行單位,雖然沒有什麼特別的能力,不過可以對空對地,加上其不錯的移動速度,是十分好用的輔助兵種。 Lookout 是 Minotaur 可以用來對空的偵察塔。 Minotaur 種族英雄的技能中有 Ferocity 並且有自我醫療的方式,十分適合使用戰士類的英雄,所以可以考慮選擇戰士類的英雄,例如 Warrior。 因為 Minotaur 的種族技能中有 Pyromancy 法術,可以考慮 Pyromancer 這個職業。 如果想要嘗試團隊型的法師英雄,那麼可以嘗試 Illusionist(因為 Mutate 法術可以將對手的基本兵種變成無害動物, 再配合 Minotaur 的食用無害動物自我醫療)。 另外可以嘗試的英雄職業為 Elementalist,這是 Barbarian 和 Minotaur 這二個種族可以嘗試的英雄, 因為 Minotaur 的種族技能為 Pyromancy 法術,Barbarian 的種族英雄技能中有 Ice Magic, 雖然 Elementalist 要到高等級才有比較好的表現,不過想要挑戰的可以嘗試。 另外,如果你真的受不了 Thrall,Barbarian 和 Minotaur 這二個種族還可以考慮嘗試 Ranger, 除了有 Taming 技能加強 monsters(Barbarian 加強 War Dog,Minotaur 加強 Basilisk), 而 Griffonmaster 也適合 Minotaur,還可以使用 Nature Magic 的 Summon Treant 嘗試使用其它的 builder。

Orc 生產速度不慢,非飛行單位都有免疫 Disease 的優勢,但是對於精神效果的對抗性較差。 戰鬥單位組合包含初階步兵 Orc 與高階步兵 Ogre,初階弓箭手 Kobold Sniper 與高階弓箭手 Troll, 騎兵 Wolf Rider,法師 Goblin Shaman 以及攻城武器 Gobshooter。 Goblin 則是其偵查步兵,攻擊與防守能力都不出色,但是擁有一定機率會散播 Disease 的能力。 Goblin Chief 是高階步兵,可以召喚一群 Goblin,如果傾向於採用人海戰術可以採用。 Giant 則是 Orc 的將軍,除了轉化 (Convert) 能力還可以造成敵人 Fear。 Bat 是 Orc 的初階飛行單位,只能用來對空,是適合用來偵查的兵種。 Harpy 是 Orc 的高階飛行單位,有 Poison 能力並且可以施展 Drain Mana 技能,但是只能對地。 在 Battleyard 中的 No Pain! 需要儘快研發,可以提高對 physical missiles 的 resistance。 Orc 在研發 Shaman research 之後可以建造對空的 Totem 補強防空, 但是注意 Orc 所有的建築都有一個嚴重的缺陷,那就是建築無法花錢修理 (Repair) ,只能嘗試使用 Earthpower 法術回復! Orc 在遊戲設計上怪異的點是雖然其種族英雄技能有 Ferocity, 但是如果將英雄支援的單位或者是技術研發分為戰士型(Healing 研發或者是有醫療的方式)、 法師型(Summon Mana 或者是 Meditation 研發), 或者是加強士氣、增加資源(MoraleIncome 或者是 Trade 這些研發或者是類似的項目與支援, 或者有增加資源的建築與單位), Orc 都沒有這方面的設計,又因為 Orc 已經有良好的戰鬥單位組合,所以可以考慮以團隊輔助為主的英雄, 在戰鬥輔助方面可以考慮 Thief,在加強建築以及增加資源方面可以考慮 Tinker。 如果想要改善建築修復的問題,可以考慮 Runemaster(注意 Runic Lore 技能對於 Orc 沒有幫助,所以可以不用學習)。 因為種族英雄的法術為 Chaos Magic, 也可以考慮使用 Deathknight 或者是 Shaman 輔助戰鬥。 考慮到種族英雄技能中有 Ferocity,雖然沒有英雄支援的單位或者是技術研發,也可以嘗試戰士類的英雄職業, 例如 Warrior 或者是 Daemonslayer。

Ssrathi 為三代新增的種族。主堡並不生產工人,而是建造 Worker Sect 後才在 Worker Sect 生產 Chameleon。 Chameleon 是高效率的工人,在研發 Construction 技能之後則是效率最高的工人。 要注意的是,Ssrathi 一般單位通常都可以使用 Poison 或者相關的技能,而 Ssrathi 的 Tower 也具有 Poison 攻擊。 Snakeman 是 Ssrathi 的初階步兵。 Ssrathi 並沒有弓箭手或者是遠程攻擊兵種,而是使用法師 Snakepriest 作為替代品, Snakepriest 在早期就可以生產並且投入戰場(並且有 Cauterize 法術可以略為恢復生命值), 最好在 Sacred Pool 研發 Power of Couatl(總共有 3 級)加強 Snakepriest, 可以攻擊距離 +2, +4 以及 +6。Lizard Rider 則是其移動速度快速的騎兵。 Triceratops 與 Tyrannosaurus Rex 是 dinosaurs,是有較高血量的單位。 Dragonfly 是 Ssrathi 的初階飛行單位,具有 Poison 能力,但為只能對空的兵種。 Pterodactyl 是 Ssrathi 的高階飛行單位,擁有良好的攻擊力,但為只能對空的兵種。 Naga 是 Ssrathi 的將軍,為遊戲中可以渡水的單位,除了轉化 (Convert) 能力還可以造成敵人 Fear。 Couatl's Favor 是第三級主堡的研發項目,可以讓 Ssrathi 的部隊 +4 combat。 雖然 Poison Magic 是 Ssrathi 的種族英雄技能,但對於 Ssrathi 而言並沒有技能十分符合的英雄, Defiler 的技能設計偏向 Plaguelord,Lichelord 對於 Ssrathi 而言只是勉強可用而已。因為 Snakepriest 具有 Cauterize 法術的關係, 可以考慮選擇戰士類的英雄,例如 Warrior。 一個有趣的英雄選擇是 Dragonslayer,如果在 unofficial patch 會非常適合,因為 Dragon Master 被修改為其技能,與 Ssrathi 種族英雄技能相符。 因為 Ssrathi 有 mana regeneration 研發的支援,如果想要偏向法師類的,可以考慮 Healer 使用英雄加強醫療的部份。 如果想要嘗試輔助類的英雄,可以使用具有 Running 技能的 Thief。還可以考慮的英雄職業為 Shaman, 雖然 Chaos Magic 前面學習的法術效果都是隨機的,但是後期可以使用 Morph Resources 交換資源, 以及使用 Wildfire 與 Chaos Plague 法術攻擊敵人。

Dark Dwarf 是二代新增的種族,其大多數單位移動速度稍慢。 Dark Dwarf 主堡 Furnace 並不生產工人,而是由 Guild 生產 Engineer。 Engineer 是高效率的工人,經過在 Ancestral Hall 研發升級後可以使用 Earthpower 法術,同時 Engineer 如果進入礦產挖礦,會被計算為放入 2 個工人。 在兵種上 Dark Dwarf 缺少騎兵和法師單位,使用多種可對空對地的 Golem,包含 Stone Golem, Iron Golem 以及 Bronze Golem; 以及擁有不錯的攻城武器,例如 Ballista 主要用途是用來對抗步兵,當對抗使用大量生產的種族時,可以生產 1 到 2 隻作為輔助, 與只能對地的 Flame Cannon 以及可對空對地的 Hellbore。Iron Golem 擁有召喚 Firebomb 的能力。 Bronze Golem 是 Dark Dwarf 的將軍,除了轉化 (Convert),還有一項能力是 scavenge building rubble for resources, 施展後可以從敵人被摧毀的建築取得資源。 如果以 Golem 作為主力,單位生產資源主要是使用 Stone (Stone Golem) 和 Metal (Iron Golem),需要注意的是 Golem 的弱點是 Electric 類型的攻擊。 另外,Golem 無法駐紮 (garrison) 到 Tower 中進行防守,這是 Dark Dwarf 的潛在弱點。 Dark Dwarf 的初階飛行單位 Firebat,可以用來對空以及攻擊建築。 Dark Dwarf 的高階飛行單位為 Wyvern,可以研發 Golden Wyvern 提升移動速度,也是其少數移動速度快的兵種。 Dark Dwarf 除了 Tower,還有主堡升到第三級以後可以建造對地的炮塔 Mortar。 另外,因為設定上 Dark Dwarf 是為了躲避大瘟疫而遷徙結果被 Lord Bane 抓到而出現的種族, 所以 Ancestral Hall 可以用來生產 Wraith 和 Shadow,但是無法像 Undead 一樣可以讓 Wraith 升級, 所以一般而言如果要生產,都會研發升級以後生產 Shadow。 在考慮英雄技能以後,Tinker 是個十分適合 Dark Dwarf 的英雄職業。 如果想要試著使用法師類的英雄,可以考慮 Alchemist。因為種族英雄的法術為 Chaos Magic, 也可以考慮使用 Deathknight 或者是 Shaman 輔助戰鬥。 另外也可以考慮的英雄職業為 Runemaster(注意 Runic Lore 技能對於 Dark Dwarf 沒有幫助,所以可以不用學習), 使用 Rune Magic 以及 Quarrying 技能作為輔助團隊之用。

Daemon 是二代新增的種族,是個強大的種族,缺點是在初期的經濟會有一些麻煩, 擁有不少的飛行單位(Imp, Succubus, Daemon),Nightmare 是其騎兵,Salamander 則是其高階步兵,缺少攻城武器不過對於 Daemon 來說並不是大問題。 Daemon 是 Daemon 強大的飛行單位,擁有造成 Chaos 精神效果的能力。 Daemon 的初階飛行單位 Firebat,可以用來對空以及攻擊建築。 Harpy 是 Daemon 的高階飛行單位,有 Poison 能力並且可以施展 Drain Mana 技能,但是只能對地。 Harpy Hag 是 Harpy 的研發技能,可以給予 +3 combat。 Summoner 是 Daemon 的將軍,傷害類型為 Electric 傷害。 其英雄擁有 Ferocity、Regeneration 以及 Pyromancy 法術技能,在英雄的個人技能上頗為優秀。 在建築方面,除了防禦塔 Tower,也有替代的 Lightning Spire。Lightning Spire 特別的地方在於,這是可以升級的。 Summoning Tower 也是可以升級的建築(共有 3 級),在研發 Brood 之後,可以召喚最多 8 個 Quasit, 以及研發 Summoning 用來降低單位生產時間 (level 1) 與單位的生產花費 (level 2), 還有 Gate 可以用來增加新生產的單位 XP。 在設定上 Daemon 是被 Summoning 法術召喚而來的,而 Daemon 也確實是十分適合 Summoning 法術的種族, 加上 Summoner 的 Gate 技能,Summoner 是最適合 Daemon 的英雄。雖然有點惡趣味,但是如果要嘗試使用偏向戰士的英雄職業, 可以考慮 Daemonslayer。因為種族英雄的法術為 Pyromancy,所以也可以考慮使用 Pyromancer。

Plaguelord 為三代新增的種族,是個需要良好資源管理的種族(因為主堡升級、技能升級和生產可能會有資源衝突), 大多數的單位具有免疫 Disease 的能力。要注意的是,Plaguelord 沒有騎兵單位。 Plaguelord 的主堡並不生產工人,需要建立 Cess Pool 後由 Cess Pool 生產工人 Zombie, Cess Pool 還可以生產初階步兵 Ghoul 以及有一定機率會散播 Disease 的偵查步兵 Slime, 而 Ghoul 與 Slime 的科技研發則在 Laboratory。Slime 需要足夠多的數量、並且研發 Acid 升級其攻擊力才會比較好用。 Gazer、Spore 與 Eye of Flame 在 Temple of Eyes 生產,是 Plaguelord 的遠程攻擊單位。 Bone Catapult 是 Plaguelord 的攻城單位,不過通常是使用其較長的攻擊距離作為輔助。 Dragonfly 是 Plaguelord 的初階飛行單位,具有 Poison 能力,但為只能對空的兵種。 Wyvern 是 Plaguelord 的高階飛行單位,對於 Plaguelord 而言是較少使用的兵種,除了需要使用 Piercing 攻擊類型的時候。 Plague Priest 是 Plaguelord 的將軍,可以對空對地,具有免疫 Disease 的能力。 Plaguelord 有個很微妙的點,就是 Hydra Cave 可以研發科技升級為 Fire Cave 或者是 Ice Cave, 但是升級以後就無法生產 Hydra,只能生產升級以後的 Pyrohydra 或者是Cryohydra! 以英雄選擇來說,Defiler 有二個技能是用來加強 Plaguelord 的兵種(lv5 Slimemaster 與 lv15 All-Seeing Eye), 所以是還可以的選擇,但是 Ranger 的 Taming 技能對於 Plaguelord 而言有更廣泛的加強效果。考慮種族英雄有 Summoning 法術, 也可以考慮 Daemonslayer。

The Swarm 為三代新增的種族,是以大量生產士兵為主的種族。 主堡 Dunekeep 並不生產工人,需要建立 Hive 後由 Hive 生產工人 Giant Ant, 而 Hive 升級之後則可以生產更多種類的單位(注意,是每一個 Hive 都需要升級,這是 The Swarm 的潛在弱點)。 Scarab 是 The Swarm 的遠程攻擊單位,如果要生產 Scarab 那麼 Hive 至少要升到第二級。 Scorpion 是 The Swarm 的初階步兵,生產時只花費 Metal。 Scorpionman 是 The Swarm 的騎兵。 Husk 生產自 Burial Hall,擁有不錯的 missile resistance,生產時只花費 Metal。 Scorpionpriest 是 The Swarm 的將軍,除了轉化資源,擁有召喚 Fire Elemental 的能力,還可以用來輔助對抗空軍。 Wasp 是 The Swarm 的初階飛行單位,個體弱小,並不是十分可靠,不過具有 Poison 與 Assassination 能力。 Harpy 是 Daemon 的高階飛行單位,有 Poison 能力並且可以施展 Drain Mana 技能,但是只能對地。 Watcher 則是 The Swarm 可以對空對地的防禦塔替代品。 Dunekeep 在研發 Famine 技能之後可以偷取資源。在 Egg Chamber 研發 Incubation 則可以加快生產的速度。 另外,因為 The Swarm 只有少數能夠對空的單位,因此在遇到擁有大量空軍單位的種族時如何有效的對空對於 The Swarm 來說是件很重要的事情。 以英雄選擇來說,因為 unofficial patch 修改了種族英雄法術技能 (從 Necromancy 改為 Poison Magic),所以如果要符合大多數的版本,那麼是 Warrior; 如果是 1.03,因為 Necromancy 是其英雄的法術技能之一,Deathknight 是合理的選項。 如果想嘗試法師類的英雄,可以考慮 Lichelord。 Shaman 也是可以考慮的英雄職業,雖然 Chaos Magic 前面學習的法術效果都是隨機的,但是後期可以使用 Morph Resources 交換資源, 以及使用 Wildfire 與 Chaos Plague 法術攻擊敵人。 另外,也可以嘗試 Sage 這個法師職業,Divination Magic 是支援類型的法術, 而 The Swarm 是以大量生產士兵為主的種族,所以可以嘗試使用。

Undead 是一個需要良好操作與資源管理的種族。主堡並不生產工人,而是建造 Graveyard 後由 Graveyard 生產 Zombie。 Undead 生產方式在各種種族中是比較特別的,有一些單位並不是直接從相關建築生產, 而是從 Skeleton、Wight 或者是 Wraith 升級而來(Skeleton 可以從 Graveyard 或者是 Gravestone 生產, 再來花費資源成為 Wight 或者是 Wraith)。Wight 是 Undead 的初階步兵,只能夠對地。 Wraith 也是 Undead 的初階步兵,能夠對空對地,但是後續只能夠升級為 Shadow。 Skeleton Cavalry 則是 Undead 的騎兵單位。Skeleton 與 Skeleton Cavalry 有不錯的 missile resistance。 Shadow 是 Undead 的高階步兵,自 Wraith 變化而來。 Liche 是 Undead 的高階遠程攻擊單位,自 Wight 變化而來,同時也是法師,可以施展 Call the Dead。 Slayer Knight 是 Undead 的高階步兵,自 Wight 變化而來,擁有造成 Chaos 精神效果的能力。 Doom Knight 是強大的單位,從 Slayer Knight 變化而來,擁有造成 Chaos 精神效果的能力。 Vampire 是 Undead 的將軍,除了轉化 (Convert) 能力還可以造成敵人 Fear。 Bat 是 Undead 的初階飛行單位,只能用來對空,是適合用來偵查的兵種。 Barrow 是在二級主堡能夠建造的建築,為 Skeleton 能夠變化為 Wight 的必要建築, 並且有 Haunting (+3 speed) 與 Wailing (+3 combat) 升級 Wight 與 Shadow 的能力。 Necromancy 是其英雄的法術技能之一,是十分適合該種族的法術(第一個法術就是 Raise Skeleton, 第二個法術是 Raise Zombie), 而 Necromancer 的技能 Memories 增加 Skeleton 的 XP,Undead Legion 增加 Skeleton Cavalry 的 XP, Necromancer 是極為適合 Undead 使用的英雄。如果想嘗試戰士類的英雄,可以考慮 Deathknight。 因為 Lichelord 的英雄技能有 Necromancy,法師類的英雄還可以嘗試 Lichelord。 在缺少 Trade 交換資源的情況下 Shaman 也是可以考慮的英雄職業,雖然 Chaos Magic 前面學習的法術效果都是隨機的, 但是後期可以使用 Morph Resources 交換資源,以及使用 Wildfire 與 Chaos Plague 法術攻擊敵人。

Researches

High Elf 和 Wood Elf 有 Healing 科技可以提升 health regeneration rate。 High Elf 在建築 Healer 與 Wood Elf 在建築 Healing Orb 研發 Elcor's Balm 之後, 就可以以花費 400 Crystal 的代價回復附近大範圍部隊 HP 與治療 Poison、Disease。

Fey 和 High Elf 騎兵 Unicorn 擁有 Cure 和 Group Healing 能力, 對於戰士類英雄以及部隊來說,是很有用的單位。 Empire 的 White Mage 除了轉化 (Convert) 能力,也有 Cure 和 Group Healing 能力,是很有用的單位。 Knight 的 Archon 具有 Cure 能力,可以治療 Poison、Disease以及略為恢復生命值。 Ssrathi 的 Snakepriest 具有 Cauterise 能力,可以用來略為恢復生命值。 Minotaur 種族可以透過無害食用動物自我醫療(例如 Sheep)。

研發 Summon Mana 可以提升 mana regeneration, 包含 Barbarian, Dark Elf, Daemon, Fey, Minotaur, Plaguelord, Ssrathi, The Swarm, Undead 這些種族, 但是 Daemon 只能研發第一級,Fey 只能研發到第二級。 這個研發對於 Barbarian 這個種族有趣的地方在於,只有英雄(以及英雄的隨從們)從 Summon Mana 獲益, 但是如果要讓 Barbarian 英雄可以更快的施展法術幫助團隊,這個研發是必要的。

研發 Meditation 可以提升英雄 casting skill,第一級提升 10%,第二級提升 20%,第三級提升 30%。 包含 Dark Elf, Fey, High Elf, Wood Elf 這些種族,但是 Fey 只能研發到第二級。

一些種族有 Income 可以研發, 包含 Barbarian, Dark Dwarf, Dwarf, Empire, Fey, High Elf, Knight, 研發後可以自礦產增加收入 (第一級 +1,第二級 +2,第三級 +4,第四級 +6); 其中 Dark Dwarf 和 Empire 可研發到第二級,Barbarian, Dwarf, High Elf, Kight 可研發到第三級, Fey 可研發到第四級。另外,Daemon 的 Hard Labor 也具有一樣的效果, 研發後可以自礦產增加收入 (第一級 +1,第二級 +2,第三級 +4)。

一些種族有 Trade 可以研發,包含 Barbarian, Dark Dwarf, Dwarf, Empire, High Elf, Knight, Wood Elf,功用是讓玩家可以交換資源(例如 Gold 交換 Metal),不過交換後只能換到約 50% 的資源。

另外,Dark Elf, Orc 與 Undead 有 Slavehorde 這項研發,召喚費用最多為 10 個 Thrall 250 Gold。 Dark Elf 在研發 Slavehorde 之後可以在 Reformatory 召喚 Thrall。 Orc Prison 除了生產 Troll,在研發 Slavehorde 之後還可以召喚 Thrall。 Undead Undead 在研發 Slavehorde 之後可以在 Cage 召喚 Thrall。

Morale 在遊戲中是一項支援機制,可以用來增加 army limit,略為加強隊伍的攻擊速度,以及延伸 Command Radius 的範圍。 研發 Morale 可以提升部隊的 Morale,效果為 Morale +3, +6 與 +9, 包含 Dwarf, Empire, Minotaur, The Swarm, Wood Elf 這些種族有這個研發。 Ssrathi 也有類似的研發,Warmth 可以提升部隊的 Morale +5。 Knight 的研發 Order of the Lion 可以增加英雄 Morale +2。 另外,有幾個作戰單位在戰場上可以提升已方的 Morale,包含 Knight 的 Knight lord 可以帶來 +2 Morale, 與 Barbarian 的 Warlord 可以帶來 +1 Morale。

英雄有 command radius 的設計(也就是英雄轉化、使用法術的有效範圍),可以按 r 查看目前的範圍。 Undead 的研發 Dark Lord 可以 +8 英雄 command。

大多數的種族都有加強攻擊、防守等方面的研發。 WeaponsmithArmorer 是一些種族都有的科技研發項目,共有二級研發。 前者 +5 melee damage 與 +10 melee damage,包含 Dark Dwarf, Dwarf, Empire, Knight, Undead 這些種族有這個研發。 後者 +5 armor 與 +10 armor,包含 Dark Dwarf, Dwarf, Empire, Knight 這些種族有這個研發。 在研發 Weaponsmith 和 Armorer 之後,Dark Dwarf 與 Dwarf 還可以研發 Mithril; Knight 則有 Full Plate Armor 可以提升騎兵的 armor。 Undead 則是在 Weaponsmith 之後還可以研發 Dark Mithril。 其它種族也有類似的研發, Minotaur 的 Iron Clad HornsIron Shod Hooves 各提供了 +10 melee damage, Shield of Sartek 提供了 +5 armor 與 +10 armor。 Fey 的 Faerie Blade 研發後可以 +5 melee damage,Panoply 提供了 +5 armor 與 +10 armor。 Daemon 的 Intangibility 提供了 +5 armor 與 +10 armor。 Barbarian 的 Magical Tattoos 提供了 +5 armor。

FletcherBowyer 為加強弓箭手的科技研發, 前者 +5 damage,後者 +2 range,包含 Dark Elf, Dwarf, Empire, High Elf, Knight, Wood Elf 這些種族有這個研發。 Flaming Arrows 則是可以將攻擊類型從 Piercing 變為 Fire, 包含 Dark Elf, Empire, High Elf, Knight, Wood Elf 有這項研發。 Fey 也有類似的研發,Faerie Sight 這項研發提供了 Faerie Dragon, Leprechaun, Pixie 以及 Sprite 這些兵種 +2 range。

對於大多數的種族來說,關於視野與地圖迷霧 (Fog of War) 有二個相關的研發, 前者為 Eagle Eye,後者為 Farseeing。 可以研發 Eagle Eye 的種族包含 Barbarian, Fey, Minotaur, Orc, Ssrathi, The Swarm, Wood Elf, 效果為視野距離 +2, +3 與 +4。可以研發 Farseeing 的種族包含 Fey, Minotaur, Ssrathi, The Swarm, Wood Elf, 用來去除地圖迷霧。Daemon 的 Daemonic Sight 也是視野相關的研發,效果為視野距離 +2 與 +4。

Minotaur 與 Dwarf 有 Dwarven Brew 這項研發, Minotaur 在 Ale Store 研發,Dwarf 在 Brewery 研發,功用是花費某些 Gold 作為代價, 暫時提升 Combat 與 Speed,並且暫時免疫四種精神效果的狀態和二種疾病, 但是之前如果已經處於四種精神效果或者二種疾病的狀態中,那麼並沒有移除的能力。 在與敵人大會戰之前或者需要提升作戰單位的移動速度十分有用(特別是對沒有醫療能力以及移動速度不快的 Dwarf 而言)。

Barbarian 與 Minotaur 有 Berserker 這項研發, Barbarian 在 Altar of Tempest 研發並且對 Barbarian 與 Reaver 有用, Minotaur 在 Altar of Sartek 研發並且對 Minotaur, Axe Thrower 與 Minotaur Shaman 有用, 功用是啟動後,選定的單位將著火,持續對單位造成傷害,但同時獲得 +4 speed, +6 combat 與 +15 fire resistance。

Heroes

每個種族的英雄都有其各自的技能,加上英雄職業專長的技能,就組成了一個英雄能夠學習的技能表。 如果你選擇的種族英雄與你選擇的職業專長技能相同,那麼玩家將獲得 Synergy Bonus,使該技能在 1 級時可用, 並且你的技能也會獲得加成。

英雄具有下列四種基本屬性:

  • Strength
    • +1 Combat per 2 points of Strength (Every odd level)
    • +1 Damage per point of Strength
    • +3 Hit Points per point of Strength
    • +1 Life Regen (per 20 sec) for every 3 points of Strength (1,4,7,etc)
  • Dexterity
    • +1 Movement Speed per 2 points of Dexterity (Every odd level)
    • +1 Resistance per 2 points of Dexterity (Every even level)
    • +1 Armor per 4 points of Dexterity
    • -1 Second to Conversion Time per point of Dexterity (min 10 sec’s)
  • Intelligence
    • +3 Mana Points per point of Intelligence
    • +1 Mana Regeneration (per 20 sec) for every 10 points of Intelligence
    • +1 Initial Troop XP per 2 points of Intelligence (Every even level)
    • +3% Spellcasting Chance per point of Intelligence
  • Charisma
    • +1 Command Radius per 4 points of Charisma
    • +1 Morale per 2 points of Charisma (at 2,4,6,etc…)
    • +1% Discount per point of Charisma over 5
    • +1 Retinue Slot for every 4 Points of Charisma

一名英雄最多可以有 8 名隨從 (Retinue),使用 Charisma 計算的 Army Setup Point 決定隨從的人數。

英雄有以下三種類型的英雄(Monk 為 unofficial patch 引入,故不在此列入):

  • 戰士:
    一開始就有 Ferocity 技能 - Chieftain, Dragonslayer, Warrior
    Warrior 擁有增加生命值的 Constitution 與提高生命值恢復率的 Regeneration;
    Chieftain 的技能 Leadership 可以提升士氣 (Morale),Barbarian King 技能用來加強 Barbarian 的 Barbarian, Rider 與 Warlord;
    Dragonslayer 的技能 Wealth 可以帶來 Gold 收入

    戰士加上法術技能的混合類型 - Daemonslayer, Deathknight, Paladin
    Daemonslayer 使用 Summoning 法術,以及 Smelting 技能增加 Metal 收入;
    Deathknight 使用 Chaos Magic 與 Necromancy 法術;
    Paladin 使用 Healing Magic 法術,Knight Protector 增加新產出的 Knight 騎兵 XP
  • 法師: 初始技能為單一系列的法術技能加上 Ritual 技能,lv25 有 Arcane Magic - Alchemist, Defiler, Druid, Healer, Ice Mage, Illusionist, Necromancer, Priest, Pyromancer, Runemaster, Sage, Shaman, Summoner
    Priest 這個職業特別的地方在於,除了一開始的 Healing Magic,lv5 的技能為另外一個法術系列 Divination。
    多種法術技能 - Archmage (Summoning, Alchemy, Divination, Illusion), Elementalist (Pyromancy, Ice Magic, Rune Magic), Lichelord (Necromancy, Poison Magic)
  • 團隊輔助(提供資源、提高士氣或者是戰鬥輔助): Assassin, Bard, Merchant, Ranger,Tinker, Thief
    Assassin 有 Wealth 可以帶來 Gold 收入、Assassin 則有一定的機率可以立刻殺掉敵人;
    Bard 有 Wealth 可以帶來 Gold 收入、Leadership 提升士氣 (Morale) 以及使用 Divination 法術輔助戰鬥;
    Merchant 擁有 Merchant 和 Trade 技能,Wealth 增加 Gold, Gemcutting 增加 Crystal;
    Tinker 的 Engineer 技能增加建築物生命值, Smelting 增加 Metal, Quarrying 增加 Stone,以及使用 Alchemy 法術;
    Ranger 一開始就有 Running 技能,Griffonmaster 加強 Griffon,Taming 加強 monsters 以及使用 Nature Magic 法術;
    Thief 一開始就有 Running 技能,Warding 加強部隊的 Resistance,以及使用 Illusion 法術

有些種族或者是英雄的技能是增加資源:

  • Gold: Wealth from Empire (race) or Assassin, Bard, Dragonslayer, Merchant (class)
  • Metal: Smelting from Daemonslayer, Tinker (class)
  • Stone: Quarrying from Barbarian (race) or Runemaster, Tinker (class)
  • Crystal: Gemcutting from Ice Mage, Merchant (class)

(注意:在一些 unofficial patch 中,Dragonslayer 被移除了 Wealth 技能, 而 Fey 種族英雄則是被增加了 Gemcutting 技能)

英雄每一個種族一開始都會有增加士氣 (Morale) 的技能,每一級都加 2 點,包含 Dwarf 的 Dwarf Lord, Empire 的 Imperial Lord, High Elf 的 High Lord, Knight 的 Knight Lord, Barbarian 的 Horse Lord, Fey 的 Dream Lord, Minotaur 的 Horned Lord, Ssrathi 的 Serpent Lord, Wood Elf 的 Forest Lord, Daemon 的 Daemon Lord, Dark Elf 的 Dark Lord, Dark Dwarf 的 Siege Lord, Orc 的 Orc Lord, Plaguelord 的 Plague Lord, The Swarm 的 Scorpion Lord, Undead 的 Skull Lord。

要注意的是,遊戲並沒有限制一定要某個種族的英雄才能夠領導某個種族, 因此不同種族的英雄領導另外一個種族是可以的(只是因為個人的習慣,我通常不會這樣做)。

遊戲中有英雄可以穿戴物品的設計(物品有 Minor, Lesser, Greater, Artifact 四個等級)。 物品可以加強或者是補足英雄不足的地方,或者因應英雄或者種族的需要使用特定的物品。 部位包含 Headgear, Body Equipment, Weapon, Shield/Banner, 2 accessories and Boots。 物品可以提供英雄額外的技能,同時有一些物品還有一定的機率可以施展一些法術。 同時遊戲中也有 Set Items 的設計,例如在劇情中可以在 New Selentia 收集 The Gifts of Couatl(英雄可以 +100 Spell Casting); 以及 The Garb of Thyatis 除了 Staff of Thyatis 外的其它三個物品可以在 Guardia, Solhaven 與 Yrm 收集到。

Name Code Details
Giant's Helm 03 Combat +12
The Stone Crown C1 Dwarf Lord +5, Casts Stoneskin at level 2 (5%), Casts Doomstones at level 1 (5%)
Circlet of Thull 3E Summoning Magic +3, Spell Casting +5
Bane's Crown 2A Skull Lord +2, Casts Scare at level 1 (10%)
Helm of Might DB Armor +10, Combat +10, Spell Failure -5
Royal Runemail 27 Armor +25, Health +20(劇情模式中,如果是 Orc 的友好方,在 Kor 幫助他們之後可以拿到這個物品)
Ultimate Cloak of Protection A7 Resistance +15, Magic Resistance +10, Armor +5
Armor of Brilliance D5 Armor +5, Resistance +5, Spell Casting +10
Summoner's Robe C4 Summoning Magic +2, Resistance +5, Magic Resistance +5
Fey Cloak 62 Magic Resistance +10, Fire Resistance +10, Cold Resistance +10 (劇情模式中,在 Twilight Woods 幫忙 Fey 以後取得)
Orc King's Blade 0C Slashing Damage +15, Combat +6
Ogre's Blade BD Slashing Damage +20, Man Slayer +1
The Stinger CF Piercing Damage +15, Casts Spray Poison at level 1 (5%)
Sun Staff 9C Fire Damage +10, Casts Pillar of Fire at level 1 (5%)
Staff of Zhur CB Crushing Damage +10, Necromancy Magic +3, Memories +3(劇情模式中,可以在 Zhur 取得這個物品)
Staff of Regret D4 Crushing Damage +10, Lore +4
Plaguesword AF Slashing Damage +20, Casts Spray Poison at level 2 (5%), Spell Failure -5
Iceblade 69 Cold Damage +25, Spell Failure -5
Banner of Frost BC Fire Resistance +20, Mana Regen +20, Casts Hand of Ice at level 1 (8%)
Lost Banner of Lysea 4C Command +4, Imperial Lord +7
Woodland Banner 49 Morale +2, Guardian Oak +4
Orcish Banner 2B Orc Lord +4
Banner of Zhur CC Skull Lord +2, Undead Legion +2(劇情模式中,可以在 Zhur 取得這個物品)
Plagueshield 64 Chaos Magic +2, Casts Chaos Plague at level 1 (5%), Spell Failure -10 (劇情模式中,可以在 Sserin Jungle 取得這個物品)
Horn of K'Varr B3 Combat +2, Speed +2, Life Regen +40
Tome of Pure Light 40 Healing Magic +3, Casts Purify at level 1 (5%)
Orb of Healing 67 Health +20, Life Regen +20, Casts Heal Self at level 1 (5%) (劇情模式中,在 Silvermyr 幫助 Wood Elf 之後可以拿到這個物品)
Ring of Heaven C0 Life Regen +20, Casts Purify at level 1 (5%), Spell Range +20
Orb of Etheria 4F Morale +5, Combat +5, Casts Soul Flame at level 5 (5%)
Fire Giant's Horn AB Casts Resist Fire at level 1 (5%), Combat +3, Melee Damage +4
Tome of Knowledge 5F Divination Magic +6, Spell Casting +5
Tome of Change 60 Chaos Magic +6, Spell Casting +5
Tome of Lies 61 Illusion Magic +6, Spell Casting +5
Orb of Godly Power 88 Health +60, Spell Casting +5
Greater Orb of Protection 83 Armor +15, Spell Casting +5
Shaman Stones 66 Spell Casting +15, Electric Resistance +10
Dragonstones BB Dragon Master +2, Morale +1, Magic Resistance +5
Ice Queen's Harp 39 Morale +3, Cold Resistance +10
Ultimate Troll Ring 72 Life Regen +100
The Vault Key 97 Wealth +2
Leprechaun's Lyre B0 Wealth +4, Magic Resistance +5, Morale -1
Boots of the Tundra 4E Speed +2, Cold Resistance +10, Spell Casting +10
Elven Boots A3 Speed +3, Resistance +5
Boots of Slime C2 Speed +2, Poison Magic +2

Spells

魔法有以下的法術類別 (Time Magic 為 unofficial patch 引入,故不在此列入):

  • Alchemy - A sphere of magic specialised in creating Golems and Items.
  • Arcane Magic - A sphere of magic that improves other magics or the hero himself.
  • Chaos Magic - A mystic magic that summons the fickle powers of chaos. This power manipulates the stats of others.
  • Divination Magic - A sphere of magic focusing on the experience of the hero's followers.
  • Healing Magic - A sphere of magic specialised in healing allies and destroying Evil creatures.
  • Ice Magic - A sphere of magic which summons the power of ice to bend into a force of whatever the hero deigns to use it for.
  • Illusion Magic - A sphere of magic specialised in creating distractions for Enemies.
  • Nature Magic - A sphere of magic specialised in summoning beasts and controlling nature.
  • Necromancy - A sphere of magic specialised in summoning undead creatures.
  • Poison Magic - A sphere of magic specialised in inflicting Poison and Disease on enemy units.
  • Pyromancy - A sphere of magic mostly specialised in Offense.
  • Rune Magic - A sphere of magic that controls the earth and structures upon it.
  • Summoning Magic - A sphere of magic specialised in controlling and summoning Demons and other outworldlers.

要注意的是,多個法術系列都有召喚某些單位的能力(包含 Alchemy, Divination Magic, Illusion Magic, Nature Magic, Necromancy, Poison Magic, Pyromancy, Rune Magic, Summoning Magic), 而使用法術召喚的單位一樣算在 Army Limit 中,也就是如果到達限制數目,英雄會無法順利召喚。 另外,雖然 Illusion Magic 召喚的單位只是攻擊力為 1 的幻影(但是其它方面例如 health points 與精神效果是相同的), 但是一樣受到影響。

英雄都是近戰 (melee) 類型,除了使用魔法暫時變成遠程(例如 Ice Magic 的 Ice Floe), 以及使用技能(例如 unofficial patch 中 Pyromancer 的其中一項技能從 Demolition 被修改為遠程的 Fire Missile)。 另外,使用 Pyromancy 的 Firebreath 可以給與施法者以外的附近部隊暫時有造成 10 點傷害的遠程 Fire 攻擊。

通常每場戰役英雄都有 4 個 Health Potions 與 4 個 Mana Potions, 按 h 可以使用 Health Potion,按 m 可以使用 Mana Potion。Alchemy 法術中的 Brew Potion 可以用來創造新的 Health Potion; 而 Healing Magic 的 Heal Self, Cure, Heal Group, Major Healing, 與 Nature Magic 的 Gemberry,和 Pyromancy 的 Cauterize 可以用來恢復 health points。 Chaos Magic 的 Morph Health 則是給與部隊 +30 到 -30 之間的 health points(也就是可能補血也可能扣血)。

Healing Magic 的 Cure 與 Poison Magic 的 Antidote 可以移除疾病(不管是 Poison 或 Disease)。 Poison Magic 的 Immunity 則是使用後施法者可以暫時免疫疾病。 Ice Magic 的 Calm 可以移除精神效果的狀態。Healing Magic 的 White Ward 可以暫時免疫精神效果。

Illusion Magic 的法術 Scare 可以讓看到施法者的敵人 Fear,Awe 可以讓看到施法者的敵人處於 Awe 的精神效果, Dragonfear 可以製造龍的幻影造成 Terror 的精神效果。

有些法術可以提高 Armor 或者是 Resistance,包含 Pyromancy 的 Resist Fire 給予施法者 +25 Fire Resistance; Healing Magic 的 White Ward 給予周圍部隊 +5 Resistance; Divination Magic 的 Elemental Lore 給予施法者 +10 Resistance 和 Defense Lore 給予施法者 +10 Armor; Rune Magic 的 Stoneskin 給予施法者 +10 Armor,Resist Magic 給予施法者 +25 magic protection, 與 Resist Missile 給予施法者 50% missile resistance(Fandom 網頁上的 immune 在 1.03 是錯誤的, 不確定是否為 unofficial patch 的修改);Ice Magic 的 Ice Armor 給予施法者 +5 Armor; Illusion Magic 的 Shadowform 給予施法者 +1 Speed, +5 Armor and +5 Resistance。

有些法術可以用來降低對手的移動速度或者攻擊速度,Ice Magic 的法術 Freeze 可以降低移動速度 2 點並且降低攻擊速度 20%; Nature Magic 的法術 Entangle 可以降低移動速度 4 點。

另外,Nature Magic 的 Shillelagh 可以給予施法者 +5 combat。 Healing Magic 的 Blessing 可以提高施法者的士氣 (Morale) 2 點, Invigorate 可以提高附近友軍的移動速度 2 點。Chaos Magic 的法術 Morph Speed 其效果是隨機的, 效果從 -3 到 3 之間隨機決定。

Necromancy 的法術 Vampirism 可以讓友方單位獲取偷取生命的能力,+2 hits per attack。

Necromancy 的法術 Black Portal 在召喚 Black Portal 之後在附近使用可以提升法術 1 個等級。 Summoning Magic 的法術 Circle of Power 在召喚 Circle of Power 之後在附近使用可以提升法術 1 個等級。

Summoning Magic 的法術 Phantom Steed 可以用來加強騎兵;Blink 則是可以隨機的改變自己到附近的位置; Home Portal 則是傳送施法者到一開始的啟始位置。

Alchemy 的法術 Acquire 可以立即轉化附近的資源,在搶奪資源時是很有用的法術。 Alchemy 與 Rune Magic 都有 Summon Guardian 這項法術,雖然有時間限制,但是被視為建築,在臨時需要防守建築的情況十分好用。 Rune Magic 的法術 Dig 可以降低建造建築的時間 20%,是一項有用的法術。

如果使用的種族沒有 Trade 研發項目可以用來交換資源(例如 Gold 交換 Metal,不過交換後只能換到約 50% 的資源), 二個法術系列的法術也有同樣的效果,一個是 Alchemy 的 Transmute,一個是 Chaos Magic 的 Morph Resources

有些法術可以用來改變日夜或者是氣候。 Ice Magic 的 Storm 法術可以將天氣改為 thunder 與 rain。 Nature Magic 的 Change Weather 法術可以將天氣改為 night/day/fine/rain。 Necromancy 的 Darkstorm 法術可以將天氣改為 night 並且將其設定為 rain。

當然,也有一些法術是在施法範圍內直接造成傷害的法術,下面是一些例子。 Arcane Magic 作為輔助用的法術系列,Destruction (100 Mana) 是其對敵方單位與建築造成大量傷害的法術。 Chaos Magic 的 Wildfire (32 Mana) 法術可以造成施法範圍內的敵人 50 點 Fire 傷害; Chaos Plague (70 Mana) 法術將施法範圍內的敵人目前的生命值刪減 50% 並且處於 Disease 的狀態。 Ice Magic 與 Necromancy 的 Ring of Ice (35 Mana) 法術可以造成施法者周圍的敵人 40 點 Cold 傷害。 Ice Magic 的 Ice Storm (65 Mana) 法術可以造成施法範圍內的敵人 100 點 Cold 傷害。 Nature Magic 的 Call Lightning (35 Mana) 法術可以造成施法範圍內的敵人 60 點 Electric 傷害。 Poison Magic 的 Spray Poison (30 Mana) 法術可以造成施法範圍內的敵人 40 點傷害。 Pyromancy 的 Pillar of Fire (40 Mana) 法術可以造成敵人 120 點 Fire 傷害; Armageddon (75 Mana) 法術可以造成施法範圍內的敵人 100 點 Fire 傷害。 Rune Magic 的 Doomstones (16 Mana) 法術可以造成施法範圍內的敵人 30 點 crushing 傷害。 Healing Magic 的 Purify (20 Mana) 法術可以造成施法範圍內的 Evil 單位 50 點 Magic 傷害。 Divination Magic 與 Summoning Magic 的 Banish (30 Mana) 法術可以殺掉所有 extra-planar level 1-2 的敵人, 例如 Demons, Elementals 與 Archons。

Hotkey

按鍵:
F12 = Pause game
Alt + g = Game menu
Ctrl + 1 ~ 9 = Define a group

. (dot) 鍵可以用來選擇正在閒置的 builder(包含英雄在內)。
Ctrl + a = 選擇全部
Ctrl + h = 選擇英雄
S = Open Spellbookc
開啟 Spellbook 之後選擇子分類 -
h = Healing Spells
s = Summoning Spells
d = Druidic/Nature spells
i = Illusion Spells
n = Necromancy Spells
p = Pyromancy Spells
a = Alchemy Spells
r = Rune Spells
e = Ice Spells
x = Chaos Spells
z = Poison Spells
v = Divination Spells
c = Arcane Spells
Cast spell from open Book = 1, 2, 3, ... 0
F1 ~ F8 可以用來設定施法快速鍵。

2024/11/22

PugiXML

PugiXML 是一個 C++ XML parser 函式庫,支援 DOM-like interface 與 XPATH 1.0 標準。 PugiXML 在是否容易使用、執行速度以及支援功能中取得良好的平衡,其中一個特點就是容易與其它程式整合, 將 pugixml.cpp, pugixml.hpp 與 pugiconfig.hpp 複製到原始碼目錄下就可以開始使用了。

下面是 tree.xml

<?xml version="1.0"?>
<mesh name="mesh_root">
    <!-- here is a mesh node -->
    some text
    <![CDATA[someothertext]]>
    some more text
    <node attr1="value1" attr2="value2" />
    <node attr1="value2">
        <innernode/>
    </node>
</mesh>
<?include somedata?>

下面是載入 XML 檔案的程式:

#include "pugixml.hpp"
#include <iostream>

int main() {
    pugi::xml_document doc;

    pugi::xml_parse_result result = doc.load_file("tree.xml");

    std::cout << "Load result: " << result.description()
              << ", mesh name: " << doc.child("mesh").attribute("name").value()
              << std::endl;
}

下面的程式使用 libcurl 自網站下載 ATOM XML 的資料, 下載以後使用 PugiXML 分析並且將 title 與 link 的資料儲存為 html 格式。

#include "pugixml.hpp"
#include <cstdio>
#include <cstdlib>
#include <curl/curl.h>
#include <fstream>
#include <iostream>

int get_rss(const char *url, const char *outfile) {
    FILE *feedfile = fopen(outfile, "w");

    if (!feedfile)
        return -1;

    CURL *curl = curl_easy_init();
    if (!curl)
        return -1;

    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, feedfile);

    CURLcode res = curl_easy_perform(curl);
    if (res)
        return -1;
    curl_easy_cleanup(curl);
    fclose(feedfile);
    return 0;
}

int main(int argc, char *argv[]) {
    char *url = NULL;
    char *filename = NULL;
    char *outfile = NULL;
    if (argc == 4) {
        url = argv[1];
        filename = argv[2];
        outfile = argv[3];
    } else {
        printf("Not valid arguments.\n");
    }

    get_rss(url, filename);

    pugi::xml_document doc;
    pugi::xml_parse_result result = doc.load_file(filename);

    pugi::xpath_node_set title = doc.select_nodes("/feed/entry/title");
    pugi::xpath_node_set link =
        doc.select_nodes("/feed/entry/link[@rel='alternate']");

    std::ofstream ofile(outfile);

    pugi::xpath_node_set::const_iterator it1 = title.begin();
    pugi::xpath_node_set::const_iterator it2 = link.begin();
    while (it1 != title.end() && it2 != link.end()) {
        pugi::xpath_node node1 = *it1;
        pugi::xpath_node node2 = *it2;
        ofile << "<a href=\"" << node2.node().attribute("href").value() << "\">"
              << node1.node().text().get() << "</a><br>" << std::endl;

        it1++;
        it2++;
    }
    ofile.close();
}

參考連結

2024/10/31

Beyond 粵語歌曲歌單

Beyond 是香港搖滾樂隊,1983 年成立,原為地下樂隊,於 1987 年開始邁入香港主流樂壇,其後憑著多首膾灸人口的經典歌曲如《大地》、《真的愛你》、《光輝歲月》、《海闊天空》等成為華語樂壇其中一隊最具影響力的香港樂隊。

1980 年 8 月,吉他手黃家駒經位於土瓜灣下鄉道的嘉林琴行老闆介紹下認識鼓手葉世榮,聯同鄧煒謙(主音吉他)及李榮潮(貝斯)組成樂隊, 這支樂隊也是 Beyond 的雛型。

1983 年,為了參加《吉他雜誌》舉辦的比賽,Beyond 正式組成。經過幾次人事變動後,1984 年,黃家駒的弟弟黃家強加入成為低音吉他手;1985 年,主音吉他手黃貫中加入。同年,Beyond 在堅道的明愛中心自資舉辦《永遠等待演唱會》,翌年再推出自資卡式帶《再見理想》,之後在經理人陳健添(Leslie Chan)的協助下,從地下音樂正式進入商業流行樂壇。

Beyond 路線的衝突與問題來自於香港的音樂市場本身(背景可以參考盧國沾在 80 年代中期所嘗試發起的非情歌運動), 《亞拉伯跳舞女郎》和《現代舞台》仍然保有 Beyond 獨特風格以及鮮明的音樂特色, 但是唱片銷量並不理想。經紀人也對他們言明如果專輯再不賣, 他們就沒有發片的機會了。第三張專輯《秘密警察》嘗試走向大眾化,《大地》有著強烈東方色彩的Rock,更是深深的唱入了聽眾的心, 成了Beyond的第一首經典名曲;而《喜歡你》成了極受歡迎的情歌之一。這張專輯銷量理想,獲得雙白金的佳績, 而專輯內的《喜歡妳》、《大地》亦成為當時的流行歌曲。

《猶豫》這張 1991 年的專輯發行前,黃家駒曾向唱片公司計劃出一張主題為非洲音樂的專輯,但被唱片公司否決。《Amani》就是原本要做的非洲音樂專輯中的歌曲,再加上其它的歌曲組成專輯,這也造成《猶豫》雖然有一些經典之作,但是歌曲風格並不一致。因此,此唱片的出版,對 Beyond 日後為了追求更多的創作自由而前往日本發展的決定埋下伏筆。

1992 年,Beyond 為了拓展自己的音樂到更多亞洲地區,開始進軍日本及台灣發展。 1992 年 Beyond 開始長居日本,起初以為日本比香港有更大的自由度去玩音樂,惟仍要裝「鄰家男孩」去得到日本樂迷的關注。 雖然他們在日本的生活孤獨,但他們在那裡認識不少的日本音樂風格,成了 Beyond 在日本發展最大的推動力。 主唱黃家駒在 1993 年在日本東京富士電視台錄制遊戲節目《想做甚麼,就做甚麼》上因為節目設計問題跌下舞台而意外去世後, Beyond 其它成員(主音吉他: 黃貫中、貝斯: 黃家強、鼓: 葉世榮)退出日本市場,並在 1994 年與滾石簽五年約,繼續以 Beyond 的名義發展。 滾石給了 Beyond 三子極大的創作空間,並且給予本身的資源支援,這也讓這個時期的 Beyond 探索了更多的音樂風格。

注:1992 年陳健添與 Beyond 因為歌曲版權發生衝突,後來更因為 Beyond 的經理人 Amuse 的介入而惹上官非,雙方關係決裂。 不過陳健添一直擔任 Beyond 的經理人直至黃家駒去世。雖然被歌迷形容為「最受歡迎樂隊的最不受歡迎經紀人」, 但是感覺上陳健添似乎是黃家駒音樂才華的真愛粉(或者說有迷之信任),可以從林子祥的《天地》成果不如預期他說的話感覺的出來 (不過我覺得是編曲的鍋,因為這首歌與《大地》《長城》是一個系列,所以編曲需要偏重東方風格才行,田震同樣曲子改編的《千秋思念》很明顯的更好)。

歌單的歌曲不固定,這只是我現在的歌單。

  • 再見理想

    原為講述舊一代玩樂隊和在夜總會伴奏的樂手的際遇,其中由黃家駒獨唱的版本收錄在 1986 年自資發行的同名專輯《再見理想》中。 由樂隊四名成員共同參與演唱的版本收錄在 Beyond 1988年發行的粵語專輯《秘密警察》中。 歌名可以有二個意思,黃家駒獨唱的版本像是再見了理想,而四名成員合唱的版本則是再見到了理想。 我推薦的是黃家駒獨唱的版本。

  • Myth

    《Myth》收錄在 1986 年自資發行的同名專輯《再見理想》中,由陳時安作詞,黃家駒、陳時安作曲,黃家駒主唱。 陳時安的英文歌詞寫的很好,在他 1985 年因為要出國念書所以退出 Beyond 之後,Beyond 就再也沒有像《Myth》這樣的長篇敘事英文歌曲了。

  • 昔日舞曲

    有一天黃家駒拿著吉他走到街上,經過天橋時,橋下有個乞丐拉住了黃家駒的吉他,這時候 Beyond 還沒有走紅,黃家駒對他說自己也沒有錢給他了。 可是那個乞丐並不是想要錢,黃家駒不懂他的意思。於是乞丐叫黃家駒坐下,向黃家駒訴說了自己昔日的理想,過去從事的事業、奮鬥的歷程以及歷經的輝煌等。 乞丐這番話使得黃家駒感慨頗深,並激勵了年輕的黃家駒在今後的音樂生涯中不斷奮鬥不斷超越自己。於是黃家駒寫了《昔日舞曲》這首歌, 以此紀念那個乞丐與他的談話,表達對音樂理想的不懈追求。這首歌收錄在 EP《永遠等待》中。

  • 永遠等待

    Beyond 演唱的一首重金屬搖滾歌曲,由黃家駒、葉世榮、黃家強、陳時安作詞,黃家駒、陳時安作曲,最早收錄於 Beyond 1986 年 3 月發行的第一張專輯《再見理想》,後收錄在 Beyond 1987 年 7 月發行的同名 EP《永遠等待》中。

  • 亞拉伯跳舞女郎

    Beyond 第一張商業專輯《亞拉伯跳舞女郎》的同名主打歌。 《亞拉伯跳舞女郎》是一張充滿中東風情的概念專輯,專輯中充滿幻象與歷奇的場景。

  • 東方寶藏

    由《Long Way Without Friends》重新填詞並且加上中東音樂風格的版本,由黃家駒、黃貫中作詞,黃家駒作曲,收錄在《亞拉伯跳舞女郎》中。

  • 沙丘魔女

    《沙丘魔女》由黃貫中作詞,黃貫中、黃家強作曲,黃家駒擔任主唱,收錄在《亞拉伯跳舞女郎》中。

  • 無聲的告別

    《無聲的告別》由黃家強作詞,黃家駒、劉志遠作曲,黃家駒擔任主唱,收錄在《亞拉伯跳舞女郎》中。 鍵盤手劉志遠在一起製作了《亞拉伯跳舞女郎》與《現代舞台》二張專輯後離隊,這首歌也是他離隊時其它四人對他唱的歌。

  • 追憶

    《追憶》由黃家駒作詞作曲,黃家駒擔任主唱,收錄在《亞拉伯跳舞女郎》中。

  • 隨意飄蕩

    《隨意飄蕩》由黃家強作詞,黃家駒作曲,黃家駒擔任主唱,收錄在《亞拉伯跳舞女郎》中。 這是 Beyond 比較冷門的歌曲,帶著一種詩意與灑脫的曲風,十分耐聽。

  • 過去與今天

    《過去與今天》由黃家駒作詞作曲,黃家駒擔任主唱,收錄在《亞拉伯跳舞女郎》中。 香港電台電視單元劇《暴風少年》主題曲,為樂隊首次主唱的電視主題曲。

  • 孤單一吻

    《孤單一吻》由黃家強作詞,黃家駒作曲,黃家駒擔任主唱,收錄在《亞拉伯跳舞女郎》中。 這是一首具有西班牙風情的歌曲,吉他部分用了黃家駒十分喜歡的弗拉門戈方法來演繹的。

  • 玻璃箱

    《玻璃箱》由黃家駒作詞作曲,黃家駒擔任主唱,收錄在《亞拉伯跳舞女郎》中。 歌詞以玻璃箱作比喻,形容我們活在都市所面對的困局,憤怒地坐著,獨自地叫喊,也無法衝出去,是一個絕望的世界。

  • 水晶球

    《水晶球》由黃家駒作詞作曲,黃家駒擔任主唱,收錄在《亞拉伯跳舞女郎》中。 《水晶球》的編曲很精彩、充滿張力,內容是黃家駒日後經常觸及的反戰題材。

  • 舊日的足跡

    《舊日的足跡》創作於 1985 年,歌曲靈感來自於黃家駒的一位好友 Mike Lau。 Mike Lau 故鄉在北京,為了學電影而遠赴美國, 十年後終於回到故鄉,感觸頗深。他來到香港後與黃家駒暢談自己的感想,黃家駒便將他這份思念故鄉的情懷寫進《舊日的足跡》一曲之中。 《舊日的足跡》最早收錄於 1986 年自資發行的《再見理想》中,而後在《現代舞台》中也有將前奏改為鋼琴的版本。我喜歡的是改為鋼琴的版本。

  • 天真的創傷

    《天真的創傷》由黃家駒作詞作曲,並且由黃家駒主唱。收錄在 1988 年發行的專輯《現代舞台》中。 一樣是懷念初戀,這首歌聽起來比《喜歡妳》溫暖,是一首溫暖的情歌。

  • 赤紅熱血

    《赤紅熱血》由黃家強作詞,黃家駒作曲,並且由黃家駒主唱。收錄在 1988 年發行的專輯《現代舞台》中。

  • 衝上雲霄

    《衝上雲霄》由黃家強作詞,黃家駒作曲,並且由黃家駒與黃家強主唱。收錄在 1988 年發行的專輯《現代舞台》中。 這是黃家駒及黃家強兄弟首支合唱歌曲。

  • 冷雨夜

    《冷雨夜》由黃家駒作曲。原本黃家駒在完成曲調以後覺得太過商業化而沒有採用,不過黃家強聽到該曲的小樣之後,非常喜歡這首歌,因此自己填詞並挑選了它收錄進 Beyond 樂團的專輯裡。 在 1991 年的演唱會裡,黃家強在《冷雨夜》表演的貝斯獨奏是為人稱道的經典。國語版為《緩慢》。

  • 現代舞台

    《現代舞台》由劉卓輝作詞,黃家駒、黃貫中、劉志遠作曲,黃家駒主唱。收錄在 1988 年發行的專輯《現代舞台》中。

  • 城市獵人

    《城市獵人》由翁偉微作詞,黃家駒作曲,黃家駒主唱。收錄在 1988 年發行的專輯《現代舞台》中。 曲名源自當時日本人氣漫畫《城市獵人》。

  • 大地

    《大地》(1988 年粵語、1990 年國語)由黃家駒作曲,由黃貫中主唱(粵語及國語)。 《大地》歌詞隱喻兩岸中國人長年分隔的骨肉分離的滄桑。

  • 衝開一切

    《秘密警察》由黃貫中作詞,黃家強作曲,黃家駒主唱,收錄在 1988 年發行的專輯《秘密警察》中。 《衝開一切》、《秘密警察》、《喜歡你》幾首歌都是 Beyond 的經典代表作。

  • 秘密警察

    《秘密警察》由黃家駒作詞作曲並且主唱,收錄在 1988 年發行的專輯《秘密警察》中。

  • 未知賽事的長跑

    《未知賽事的長跑》由翁偉微作詞,黃家駒作曲,黃家駒與黃貫中擔任主唱,這是一首重金屬音樂的歌曲,收錄在 1988 年發行的專輯《秘密警察》中。

  • 喜歡妳

    《喜歡妳》是黃家駒寫給和自己已經分手的女友的一首歌。最初做音樂時,由於某些原因黃家駒不得不放棄深愛著的女友, 把時間和精力放到音樂之中,這令他十分愧疚。所以他便寫了《喜歡妳》這首歌,表達對失去愛情的苦楚。

  • 心內心外

    《心內心外》由黃家強作詞作曲,收錄在 1988 年發行的專輯《秘密警察》中。歌曲抒寫對理想愛情的憧憬和等待的寂寞, 以心內與心外的對比來凸顯內心的衝突。

  • 真的愛妳

    《真的愛妳》收錄於《Beyond IV》大碟,為該專輯的主打歌。歌曲以讚頌母愛為主題,表達了對母愛的讚揚。 雖然樂隊成員並不喜歡此曲太具商業元素,且甚少搖滾色彩,但至今此曲成為香港母親節的流行主題曲。

  • 我有我風格

    《我有我風格》收錄於《Beyond IV》大碟,黃家強作詞,黃家駒作曲,黃家強擔任主唱。

  • 曾是擁有

    《曾是擁有》收錄於《Beyond IV》大碟,黃家駒作詞作曲,黃家駒主唱。根據網路的說法,黃家駒錄完歌曲小樣後,請好友劉宏博 (Mike Lau) 轉交給前女友潘先麗 Kim。因此可以說這是為前女友潘先麗寫的歌。

  • 摩登時代

    《摩登時代》收錄於《Beyond IV》大碟,翁偉微作詞,葉世榮作曲,黃家駒主唱,林楚麒和聲。這首歌是一首 Beyond 描繪現代都市景象的一首歌,表達了人們不願去承受當下季節的苦悶,內心默默屏蔽周圍的荒謬,只想自醉。

  • 與妳共行

    《與妳共行》收錄於《Beyond IV》大碟,黃家強作詞,黃貫中作曲。這首歌是 TVB 電視劇《淘氣雙子星》第 8 集片尾曲。

  • 逝去日子

    《逝去日子》收錄於《Beyond IV》大碟,劉卓輝作詞,黃家駒作曲。這首歌是 TVB 電視劇《淘氣雙子星》主題曲。

  • 午夜迷牆

    《午夜迷牆》收錄於《Beyond IV》大碟,為電影《黑色迷牆》主題曲,獲得提名第 9 屆香港電影金像獎「最佳電影歌曲」,不過沒有得獎。

  • 最後的對話

    《最後的對話》收錄於《Beyond IV》大碟,葉世榮作詞,黃貫中作曲,黃貫中擔任主唱,歌曲以半純音樂的形式呈現。

  • 歲月無聲

    《歲月無聲》收錄於 1989 年的專輯《真的見證》。此曲原本由麥潔文主唱,最初以情歌風格編曲, 其後由 Beyond 重新以搖滾風格演繹。因為被認為與六四有關,所以成為中國禁曲 (一說是因為版權的關係,所以無法在中國音樂網站搜尋到此曲)。

  • 明日世界

    《明日世界》收錄於 1989 年的專輯《真的見證》,由黃貫中作詞,黃家駒作曲,黃貫中擔任歌曲主唱。歌曲從林楚麒的歌曲《怨你沒留下》 改編而來。

  • 交織千個心

    《交織千個心》收錄於 1989 年的專輯《真的見證》,由黃家強作詞,黃家駒作曲。 這是專輯中 Beyond 自己演繹為其它人創作的歌曲之一。原唱者為許冠傑,收錄在許冠傑 1988 年發行的專輯《Sam and Friends》中 。

  • 誰是勇敢

    《誰是勇敢》收錄於 1989 年的專輯《真的見證》,由葉世榮作詞,黃家駒作曲,原曲收錄在 1986 年的自資卡式帶《再見理想》內,這是重新灌錄的版本。

  • 勇闖新世界

    《勇闖新世界》收錄於 1989 年的專輯《真的見證》,由梁安琪、侯志強作詞,黃貫中作曲。 這是一首勵志歌曲,葉世榮在這首歌曲表現了自己的優秀鼓技。

  • 又是黃昏

    《又是黃昏》收錄於 1989 年的專輯《真的見證》,由陳健添作詞,黃家駒作曲。 這是專輯中 Beyond 自己演繹為其它人創作的歌曲之一。原唱者為鄧惠欣@小島樂隊。

  • 無悔這一生

    《無悔這一生》收錄於 1989 年的專輯《真的見證》,由盧國宏作詞,黃家駒作曲,為 TVB 電視劇《香港雲起時》主題曲。

  • 午夜怨曲

    《午夜怨曲》收錄於 1989 年的專輯《真的見證》,粵語版由葉世榮作詞,黃家駒作曲。 歌詞反應了 Beyond 組成樂團在出名之前的一些艱辛奮鬥的經歷,從走出地下樂團開始自己出資辦演唱會、出唱片的艱苦歷程,最終沒有放棄過自己的理想。國語版的作詞人為劉卓輝,收錄在 1991 年發行的專輯《光輝歲月》中。

  • 千金一刻

    《千金一刻》收錄於 1989 年的專輯《真的見證》,由黃家強作詞,黃家駒作曲,黃貫中擔任歌曲主唱。 原唱為譚詠麟,收錄於譚詠麟 1988 年的專輯《擁抱》中。

  • 無名的歌

    《無名的歌》收錄於 1989 年的專輯《真的見證》,由黃貫中作詞,黃家駒作曲,這是專輯中 Beyond 自己演繹為其它人創作的歌曲之一。 原唱彭健新,收錄在其 1987 年專輯《我的心》。這首歌是彭健新向 Beyond 邀歌,由 Beyond 作詞作曲與編曲的歌曲, 當時的 Beyond 尚未成名,可以說彭健新是慧眼識英雄。

  • 灰色軌跡

    這首歌是 1990 年劉德華、吳倩蓮主演的電影《天若有情》的插曲。

  • 光輝歲月

    《光輝歲月》的粵語版是一首讚美南非的非洲人國民大會主席納爾遜·曼德拉的歌曲,以歌頌他在南非種族隔離時期為黑人所付出的努力, 當時曼德拉在監禁 28 年後剛被釋放,光輝歲月表達他的一生。在國語版裡面,這首《光輝歲月》是為激勵年輕人努力拼搏而作, 而當中的種族議題被淡化。

  • 俾面派對

    《俾面派對》由黃家駒作曲,黃貫中作詞,收錄於 Beyond 1990 年發行的專輯《命運派對》中。 該曲諷刺了香港演藝圈的古怪現象。

  • 無淚的遺憾

    《無淚的遺憾》由黃家駒作曲,劉卓輝作詞,收錄於 Beyond 1990 年發行的專輯《命運派對》中。 這是 TVB 電視劇《笑傲在明天》的插曲。

  • 可知道

    《可知道》由黃家駒作曲作詞,收錄於 Beyond 1990 年發行的專輯《命運派對》中。 是黃家駒與宣明會一同往新幾內亞宣明會提供服務及實地考察後寫的一首歌。

  • 相依的心

    《相依的心》由黃家駒作曲,盧國宏作詞,收錄於 Beyond 1990 年發行的專輯《命運派對》中。

  • 撒旦的詛咒

    《撒旦的詛咒》由黃貫中作曲,葉世榮作詞,並且黃貫中主唱,收錄於 Beyond 1990 年發行的專輯《命運派對》中。 黃家強的拍線令歌的節奏部分很吸引。而背後的吉他節奏用了 Muting 之後,和歌本身的節奏與低音吉他很合櫬。

  • 送給不知怎去保護環境的人 (包括我)

    《送給不知怎去保護環境的人 (包括我) 》由黃家駒作曲,劉卓輝作詞,並且 Beyond 四人主唱。 這首歌是 Beyond 一首呼籲環保的公益歌曲。,收錄於 1990 年發行的專輯《命運派對》中。

  • 戰勝心魔

    《戰勝心魔》由黃家駒作曲,翁偉微作詞,並且 Beyond 四人主唱。 Beyond 樂隊主演電影《開心鬼救開心鬼》主題曲,同時收錄於 1990 年發行的專輯《命運派對》與《戰勝心魔》EP 中。

  • Amani

    《Amani》是樂團為呼籲資助非洲難民兒童,呼喚和平而創作的歌曲。

  • 堅持信念

    《堅持信念》為黃家駒作詞作曲,可以視為黃家駒在香港樂壇打拚多年的真實獨白。收錄於 Beyond 1991 年發行的專輯《猶豫》中。

  • 不再猶豫

    《Beyond日記之莫欺少年窮》的主題曲,為 Beyond 的合唱歌曲,同時也是其著名的勵志歌曲。收錄於 Beyond 1991 年發行的專輯《猶豫》中。 國語版為《候診室》。

  • 誰伴我闖蕩

    《Beyond日記之莫欺少年窮》的插曲,國語版為《十字路口》。收錄於 Beyond 1991 年發行的專輯《猶豫》中。

  • 高溫派對

    TVB 綜合節目《Beyond放暑假》主題曲,由胡人(本名陳敏生)作詞,黃家駒作曲,黃家駒、黃貫中、黃家強三人主唱。 收錄於 Beyond 1991 年發行的專輯《猶豫》中。

  • 誰來主宰

    黃家強、黃貫中作詞,黃家駒作曲,黃家強、黃貫中二人主唱,為 TVB 電視劇《笑傲在明天》主題曲,收錄於 Beyond 1991 年發行的專輯《猶豫》中。

  • 完全的擁有

    這是鼓手葉世榮在 Beyond 的第一首主唱歌曲,也是黃家駒去世前的惟一一首。葉世榮作詞,黃家駒作曲,收錄於 Beyond 1991 年發行的專輯《猶豫》中。

  • 報答一生

    《報答一生》由黃家強作曲,劉卓輝作詞,Beyond 編曲,黃貫中演唱,收錄在 Beyond 1992 年發行的精選集《Control》中, 也是惟一的一首新歌。《報答一生》是一首讚頌父愛的歌,其創作的原因是由於Beyond 樂隊成員黃貫中參演的一部電影《老豆唔怕多》,所以樂隊專門為電影創作的歌曲,寫的是一個叛逆的孩子,長大以後終於明白父親的的良苦用心。表達了對父親默默無聞和無私奉獻的讚揚。

  • 長城

    《長城》由黃家駒作曲及擔當主音、劉卓輝作詞、Beyond 和梁邦彥共同編曲、喜多郎創作前奏;日語版《THE WALL》由真名杏樹填詞; 國語版歌詞由詹德茂改編。粵語版本收錄於Beyond第8張專輯《繼續革命》,並為該大碟之主打歌;日語版本收錄於《超越》,國語版本收錄於《信念》。 黃家駒在一段由香港無綫電視為此曲製作的音樂錄像表示,寫此歌是要「描寫中國人一貫的民族意識」。在歌詞裡,長城反映一個封閉的國度,是強權暴政的產物,是犧牲了無數血肉之軀築成的,然而後人大多只會以它為榮,無視值得反思之處。歌詞是借物描寫這種民族思想和境況,並借古諷今,並非只是寫長城和遠古的中國。 因為被認為與六四有關,以及在香港 2014 「和平佔中」、「雨傘運動」成為抗議者的演唱歌曲,或者被用來影射目前的中國政治, 所以曾經(或者在某一些特別日子)是中國禁曲。

  • 農民

    《農民》原曲為《文武英傑宣言》,而後重新填詞為《農民》,有廣東話和國語部份,內容大抵是描述一個中國農民的生活,如何在艱困的生活中逆境自強。 廣東話和國語的版本卻有著極大不同。廣東話版本是由劉卓輝填詞,是對山區農民生活的影射;而國語版則由姚若龍填詞,內容更為廣泛, 是描述北方人重視固有生活的個性。

  • 不可一世

    Beyond 在香港成名後前經紀人陳健添就更加變本加厲的密密麻麻安排商業娛樂性重的工作,陳健添還因經紀人佣金和分紅和 Beyond 起糾紛, Beyond 早已厭倦陳健添這種為利是圖處處算計的人壓榨逼迫,以及他安排下過的違背意願的奉迎生活, 他們寫的《不可一世》是諷刺逼迫控制他們越緊的經紀人陳健添,而不是陳健添口中所說的諷刺電視台高層。 重新填詞的國語版《今天就做》則是表達了一種生活態度。

  • Bye-Bye

    《Bye-Bye》由黃貫中作詞,黃家駒作曲並且擔任主唱,收錄在 1992 年的專輯《繼續革命》中。

  • 遙望

    《遙望》由黃家駒作詞作曲並且擔任主唱,收錄在 1992 年的專輯《繼續革命》中。 由姚若龍重新填詞的國語版《關心永遠在》收錄在 1992 年的國語專輯《信念》中。

  • 溫暖的家鄉

    《溫暖的家鄉》由黃貫中作曲作詞並且擔任主唱。這首歌也有同名的國語版。

  • 可否衝破

    《可否衝破》由葉世榮作詞,黃家駒、黃家強、黃貫中作曲,黃家駒主唱,收錄在 1992 年的專輯《繼續革命》中。 國語版《可否衝破》收錄在 1992 年的國語專輯《信念》中。

  • 快樂王國

    《快樂王國》是一首輕快的歌曲,黃家強作詞,黃家駒作曲,黃家駒主唱,收錄在 1992 年的專輯《繼續革命》中。 國語版《年輕》收錄在 1992 年的國語專輯《信念》中。

  • 早班火車

    《早班火車》是一首表達暗戀心情的情歌,黃家駒、黃家強、黃貫中作曲,林振強作詞,黃家駒主唱。

  • 厭倦寂寞

    《厭倦寂寞》由黃家強作曲作詞並且擔任主唱,是黃家強一首精采的情歌作品。這首歌也有同名的國語版。

  • 無語問蒼天

    《無語問蒼天》由黃家駒作曲,黃家強作詞,黃家駒主唱。《無語問蒼天》帶著警醒和思考。熱血的赤子被扭曲的眾生包圍, 隨處可見的欺騙和捉弄,慾望和爭鬥。在現實和理想間該如何抉擇?問蒼天,也是問自己。

  • 無盡空虛

    《無盡空虛》由黃家駒作詞、作曲,Beyond 和梁邦彥共同編曲,收錄在 Beyond 1993 年 1 月 7 日由華納唱片發行的 EP《無盡空虛》中。

  • 海闊天空

    《海闊天空》被視為黃家駒最具代表性的遺作,同時也是粵語流行音樂的巅峰之作,收錄在專輯《樂與怒》與國語精選專輯《海闊天空》中。 這首歌是記錄 Beyond 十年心路歷程的歌曲,歌詞承載了黃家駒與樂隊赴日本發展的艱辛與對理想的堅持, 也表達了黃家駒內心深處對香港樂壇的掙扎和失望。曲帶給人們的是一種積極向上的生活態度,堅持自己的理想,永遠不放棄的信念。 當年黃家駒在編寫《海闊天空》一曲時,曾將歌詞其中一句定為「也會怕有一天會跌倒 Oh Yeah」,但黃家強認為意思不對,遂修改為「……Oh No」, 沒料到黃家駒在完成此曲後不足2個月真的意外身亡。

  • 爸爸媽媽

    收錄在專輯《樂與怒》中,由黃貫中作词,黃家駒作曲,Beyond、梁邦彥共同编曲,黃家駒擔任主唱。 Beyond 以中英方爭拗做題材,創作搖滾歌曲《爸爸媽媽》,唱出過渡期主流港人心態,像家庭吵架裡無辜孩子,盼不做用箭靶, 奈何夾在中間,無法自主。這首歌 Beyond 嘗試了不同的音樂風格。在這首歌裡黃家駒還唱了一段 RAP,展示了他過人的節奏感。

  • 狂人山莊

    收錄在專輯《樂與怒》的硬搖滾作品。在專輯《樂與怒》中 Beyond 嘗試了更多的音樂風格, 但是卻仍然能夠被大多數人欣賞,顯示了 Beyond 成熟且優秀的音樂創作能力。

  • 我是憤怒

    收錄在專輯《樂與怒》的硬搖滾作品。由黃貫中作词,黃家駒作曲,Beyond、梁邦彥共同编曲,黃家駒擔任主唱。 該曲的詞作者黃貫中認為,在 Beyond 的眾多經典作品中,只有《我是憤怒》最能代表自己。他認為《我是憤怒》很簡單、很直接,但憤怒不單單是情緒表達,是看到不公平的事情會有所反應,要講出來、要申訴,是種正義感,一種做人的堅守。

  • 全是愛

    收錄在《樂與怒》與精選專輯《海闊天空》的作品,我會放這首是因為我喜歡這首歌的前奏。

  • 命運是你家

    《命運是你家》由黃家駒作曲,黃貫中作詞,Beyond、梁邦彥共同编曲,黃家駒擔任主唱,收錄在《樂與怒》的作品。 這首歌黃家駒稱是對香港九龍皇帝曾灶財的寫照,曾灶財在香港九龍街頭塗鴉的字體自成一派,可以說也是一位傳奇人物。 這是一首民謠風格的歌曲,也可以視為對一個堅持做一件事的人的寫照,而不只是對九龍皇帝而已。

  • 和平與愛

    Beyond 一首關注第三世界的音樂作品,收錄在《樂與怒》與精選專輯《海闊天空》的作品。

  • 完全地愛吧

    《完全地愛吧》為黃家強作詞作曲並且擔任主唱的情歌,收錄在《樂與怒》裡。 日文版為《くちびるを奪いたい(我想奪取你的唇)》,為進軍日本市場的專輯《This Is Love 1》主打歌曲之一。

  • 情人

    《情人》是 Beyond 為各自的愛人創作的歌曲,不過該曲作詞人劉卓輝後來稱,這首原本叫《大陸情人》的歌曲, 其實是藉分隔兩地的感情來隱喻內地與香港的關係。

  • 妄想

    《妄想》由黃家駒作詞,Beyond 四人作曲,Beyond、梁邦彥共同编曲,黃貫中演唱。 這首歌是一首藍調風格的歌曲。

  • 走不開的快樂

    《走不開的快樂》由黃家強作詞,黃家駒作曲,Beyond、梁邦彥共同编曲,黃家駒演唱。 這首歌表達了一種積極的生活態度,曲風則帶有一些日式風格。

  • 無無謂

    《無無謂》由葉世榮作詞作曲,Beyond、梁邦彥共同编曲,Beyond 四人演唱。 曲調採用雷鬼音樂風格,加上 Beoynd 四個人都不是使用本來的聲音,而是使用類似變聲的方式演唱, 讓這首歌曲變成有些特別的搞怪歌曲,也是《樂與怒》專輯的最後一首歌。

  • 超級武器

    《超級武器》收錄在專輯《二樓後座》中,葉世榮作詞,黃家強作曲並且擔任主唱。這是一首反戰歌曲。 二樓後座是指 Beyond 在旺角洗衣街 215 號 Band 房進行創作及彩排的單位,源於成員葉世榮的家庭物業。

  • 總有愛

    《總有愛》是黃家強在 Beyond 經歷黃家駒去世的打擊後創作的歌曲, 他創作這首歌是為了感謝在 Beyond 最困難的時期依然無悔奉獻、關心支持他們的歌迷朋友, 收錄在專輯《二樓後座》中。國語版為《一輩子陪我走》。

  • 醒你

    《醒你》收錄在專輯《二樓後座》中,林振強作詞,黃家強/黃貫中/葉世榮三人作曲,黃家強主唱。 《醒你》是一首抨擊偶像崇拜文化的歌曲,以犀利的歌詞諷刺了香港人盲目追捧偶像的現象,是對粉絲為了追星的一些行為的不滿和告誡。

  • We Don't Wanna Make It Without You

    《We Don't Wanna Make It Without You》收錄在粵語專輯《二樓後座》與國語專輯《Paradise》中,黃貫中作詞作曲,Beyond 三人擔任主唱。 《We Don't Wanna Make It Without You》是懷念黃家駒之作,這是一首半演奏曲,主歌的歌詞部份空白,而副歌的部份則是由當時的 Beyond 三子合唱, 暗示黃家駒一直是 Beyond 主唱,這是一首很出彩的作品。

  • 打救你

    《打救你》收錄在粵語專輯《二樓後座》中,劉卓輝作詞,黃家強/黃貫中作曲,黃家強擔任主唱。 國語版是鄭智化填詞的《無名英雄》。

  • 冷雨沒暫停

    《冷雨沒暫停》收錄在粵語專輯《二樓後座》中,黃貫中作詞作曲並且擔任主唱。 《冷雨沒暫停》是 Beyond 第一首使用迷幻電子音樂作背景。

  • 祝您愉快

    《祝您愉快》收錄在粵語專輯《二樓後座》中,黃家強作詞作曲並且擔任主唱。國語版則收錄在國語專輯《Paradise》中。 這是黃家強懷念黃家駒之作,一首很悲傷的歌曲,很明顯的當時的黃家強尚未走出黃家駒離世的悲傷。

  • 教壞細路

    《教壞細路》由 Beyond 三人填詞,黃家強作曲並演唱,收錄在 Beyond 1995 年 6 月由滾石唱片發行的專輯《Sound》中。「細路」的意思是小孩子。《教壞細路》直白的揭露了彼時香港媒體的過度商業和虛假,也因此歌曲一發行 Beyond 就遭到了香港 TVB 的封鎖。

  • 缺口

    《缺口》由黃貫中作詞作曲並且擔任主唱,收錄在 Beyond 1995 年 6 月由滾石唱片發行的專輯《Sound》中。 這是一首懷念黃家駒之作,充滿了三缺一的遺憾和唏噓。

  • Cryin'

    《Cryin'》由黃家強作詞作曲並且擔任主唱,收錄在 Beyond 1995 年 6 月由滾石唱片發行的專輯《Sound》中。 這是一首失落無力感自述的歌曲。

  • 聲音

    《聲音》由黃貫中作詞作曲並且擔任主唱,收錄在 Beyond 1995 年 6 月由滾石唱片發行的專輯《Sound》中。 當年香港政府在大球場重建後, 實施遭噪音管制, 變相禁止歌手在大球場開演唱會, 這首《聲音》是用來諷刺當時的香港政府。

  • 逼不得已

    《逼不得已》是一首硬搖滾風格的歌曲,由黃貫中作詞,Beyond 三子作曲,黃家強主唱, 收錄在 Beyond 1995 年 6 月由滾石唱片發行的專輯《Sound》中。

  • 門外看

    《逼不得已》是一首 Funk 音樂風格的歌曲,由黃貫中作詞,黃貫中作曲,黃貫中主唱, 收錄在 Beyond 1995 年 6 月由滾石唱片發行的專輯《Sound》中。

  • 預備

    《預備》由林夕作詞,黃家強作曲並演唱,收錄在 Beyond 1997 年 4 月由滾石唱片發行的專輯《請將手放開》中。 《請將手放開》是於香港主權移交前發行,專輯是在二樓後座改建後的錄音室灌錄。

  • 回響

    《回響》由黃家強/李焯雄作詞,黃家強作曲並演唱,收錄在 Beyond 1997 年 4 月由滾石唱片發行的專輯《請將手放開》中。 這是為聾人基金會寫的歌曲。

  • 誰命我名字

    《誰命我名字》由黃貫中作詞作曲並演唱,收錄在 Beyond 1997 年 4 月由滾石唱片發行的專輯《請將手放開》中。 這是為保護動物基金會寫的歌曲。

  • 麻醉

    《麻醉》由黃偉文作詞,黃家強作曲並演唱,收錄在 Beyond 1997 年 4 月由滾石唱片發行的專輯《請將手放開》中。

  • 無助

    《無助》由葉世榮/李焯雄作詞,葉世榮作曲並演唱,收錄在 Beyond 1997 年 4 月由滾石唱片發行的專輯《請將手放開》中。 因此歌曾誤植詞曲作者(曲誤為黃家駒之作,詞誤為劉卓輝之作),所以這個歌曲曾經發生版權爭議,之後才確定詞曲作者並且釐清問題。


  • 《霧》由黃偉文作詞,黃貫中作曲並演唱,收錄在 Beyond 1997 年 12 月由滾石唱片發行的專輯《驚喜》中。 《霧》以流行搖滾的曲調呈現,吉他伴奏有重型的夢幻流行,編曲用格調化的手法。 《霧》的歌詞寫的是愛情,在迷霧中讀不懂、看不清,最後只能感嘆歲月已過。


  • 《深》由李焯雄作詞,黃家強作曲並演唱,收錄在 Beyond 1997 年 12 月由滾石唱片發行的專輯《驚喜》中。 《深》鼓機節拍和夢幻流行中,呈現一片乾淨微冷的電子音樂和節拍。

  • 驚喜

    《驚喜》由黃偉文作詞,黃貫中作曲並演唱,收錄在 Beyond 1997 年 12 月由滾石唱片發行的專輯《驚喜》中。

  • 無事無事

    《無事無事》由黃偉文作詞,葉世榮作曲並演唱,收錄在 Beyond 1997 年 12 月由滾石唱片發行的專輯《驚喜》中。 葉世榮使用 Drum Loop 創作《無事無事》,展現了音樂上的另一種新風貌。

  • 我記得

    《我記得》由林夕作詞,黃家強作曲並演唱,收錄在 Beyond 1997 年 12 月由滾石唱片發行的專輯《驚喜》中。

  • 不見不散

    《不見不散》這張 1998 年發行的專輯流露出三人創作野心,除了 Beyond 3 位成員外,還有邀請樂隊早期成員劉志遠參與, 此專輯出現三人自己的音樂個性。《不見不散》也是同名專輯中的一首歌曲,由黃貫中作詞作曲。

  • 時日無多

    《時日無多》收錄在 1998 年發行的專輯《不見不散》。《時日無多》由黃家強作詞作曲並且擔任主唱。

  • 扯火

    《扯火》收錄在 1998 年發行的專輯《不見不散》。《扯火》由黃家強作詞作曲,以力量搖滾樂曲下的印度歌詠。

  • 崇拜

    《崇拜》收錄在 1998 年發行的專輯《不見不散》。《崇拜》由葉世榮作詞作曲,以電氣搖滾呈現。

  • 無重狀態

    《無重狀態》收錄在 1998 年發行的專輯《不見不散》。《無重狀態》由郭啟華作詞,黃家強作曲並且擔任主唱。

  • 喜歡一個人

    《喜歡一個人》收錄在 1998 年發行的 EP《Action》。《喜歡一個人》由黃家強作詞作曲並且擔任主唱,其意思並非是喜歡上一個人, 而是喜歡自己一個人。國語版由周耀輝填詞,也收錄在同 EP 中。

  • Good Time

    《Good Time》是香港搖滾樂隊 Beyond 在 1999 年發行的專輯,《Good Time》是Beyond宣佈暫時解散前最後一張的專輯。 《Good Time》是《Good Time》專輯中的一首歌曲,由黃貫中作詞作曲並且擔任主唱。

  • 十八

    《十八》是《Good Time》專輯中的一首歌曲,由黃貫中作詞作曲並且擔任主唱。曲調採用民謠風格, 歌詞描述的是經歷風浪後的自己,與十八歲的自己對話的過程。如果是十八歲的自己,會怎麼理解現在的自己呢? 雖然《Good Time》銷量並不是很好,但是《十八》卻是首佳作。

  • 失蹤

    《失蹤》是《Good Time》專輯中的一首歌曲,由陳少琪作詞,黃家強作曲,黃家強主唱。歌曲講的是戀人的出走,陳少琪的詞寫的不錯。

  • 一百零一次

    《一百零一次》是《Good Time》專輯中的一首歌曲,這是一首勵志歌曲,由周耀輝作詞,黃家強作曲,黃家強主唱。

  • 褪色

    《褪色》是《Good Time》專輯中的一首歌曲,這是一首講述都市變遷的歌曲,歌詞帶著一種傷感的感覺,由黃家強作詞作曲並且擔任主唱。

  • 進化論

    《進化論》是《Good Time》專輯中的一首歌曲,這是隱藏曲目,由林夕作詞,黃貫中作曲,黃貫中主唱。

  • 抗戰二十年

    2003 年是 Beyond 成立 20 週年的日子,家強在家駒生前留下的 demo中,選了一首重新製作作為主題曲, 特別之處是歌曲直接用了 demo 中的一段作前奏,由家駒自彈自哼出旋律,到中間其他隊友加入,鑄成四子不可思議的合作。 《抗戰二十年》這首歌與《海闊天空》、《光輝歲月》均被視為 2014 年香港 6.22 民間全民投票、七一大遊行、 學界大罷課與讓愛與和平佔領中環/雨傘革命爭取自由民主的主題歌曲,同時也被一些人認為有暗示六四的歌詞, 所以《抗戰二十年》也是一首中國禁曲。

  • 長空

    《無間道2》的主題曲,也是 Beyond 正式解散前的最後一首歌,由黃家強、葉世榮作詞,黃家強作曲並擔任歌曲主唱,該曲獲得第 23 屆香港電影金像獎最佳原創電影歌曲獎。