undefined reference to和 非靜態成員引用必須與特定對象相對 的一種情況

現象

最近改一個程序,給需要給現有的一個類myClass增加一個變量m。很簡單的一件事情,卻碰到了問題。
程序結構是這樣的,主程序名爲A,使用動態鏈接庫B。需要增加變量的類在B中。增加的變量m希望myClass的myFunc函數中賦值,在B庫的另一個類裏取值。

第一個嘗試

直接在myClass的定義中增加int m。在myFunc函數中使用。還沒到編譯,vs就提示錯誤“非靜態成員引用必須與特定對象相對”,於是參考其他的用法,改成 static int m。這裏通過了。
分析一下原因:myFunc函數時static的,所以使用的m變量也應該是static。

第二個問題

下面編譯,B庫編譯通過,但是A程序卻編譯不通過,提示B.so undefined reference to ‘m’
爲什麼m只在B庫裏使用,B庫都編譯通過了,A程序爲什麼還報這個錯誤呢。
後來想到,static型的變量是需要在類外面初始化的。B類定義的外面增加了static int B::m=0。再次編譯就可以了。

總結

這個問題暴露了對static的用法的掌握。需要重溫一下static的幾個特性:
靜態成員函數只能訪問靜態成員數據、其他靜態成員函數和類外部的其他函數。
靜態成員在類的所有對象中是共享的。如果不存在其他的初始化語句,在創建第一個對象時,所有的靜態數據都會被初始化爲零。我們不能把靜態成員的初始化放置在類的定義中,但是可以在類的外部通過使用範圍解析運算符 :: 來重新聲明靜態變量從而對它進行初始化,如下面的實例所示。

引用https://www.runoob.com/cplusplus/cpp-static-members.html

C++ 類的靜態成員

我們可以使用 static 關鍵字來把類成員定義爲靜態的。當我們聲明類的成員爲靜態時,這意味着無論創建多少個類的對象,靜態成員都只有一個副本。

靜態成員在類的所有對象中是共享的。如果不存在其他的初始化語句,在創建第一個對象時,所有的靜態數據都會被初始化爲零。我們不能把靜態成員的初始化放置在類的定義中,但是可以在類的外部通過使用範圍解析運算符 :: 來重新聲明靜態變量從而對它進行初始化,如下面的實例所示。

下面的實例有助於更好地理解靜態成員數據的概念:
實例

#include <iostream>
 
using namespace std;
 
class Box
{
   public:
      static int objectCount;
      // 構造函數定義
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // 每次創建對象時增加 1
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
   private:
      double length;     // 長度
      double breadth;    // 寬度
      double height;     // 高度
};
 
// 初始化類 Box 的靜態成員
int Box::objectCount = 0;
 
int main(void)
{
   Box Box1(3.3, 1.2, 1.5);    // 聲明 box1
   Box Box2(8.5, 6.0, 2.0);    // 聲明 box2
 
   // 輸出對象的總數
   cout << "Total objects: " << Box::objectCount << endl;
 
   return 0;
}

當上面的代碼被編譯和執行時,它會產生下列結果:

Constructor called.
Constructor called.
Total objects: 2

靜態成員函數

如果把函數成員聲明爲靜態的,就可以把函數與類的任何特定對象獨立開來。靜態成員函數即使在類對象不存在的情況下也能被調用,靜態函數只要使用類名加範圍解析運算符 :: 就可以訪問。

靜態成員函數只能訪問靜態成員數據、其他靜態成員函數和類外部的其他函數。

靜態成員函數有一個類範圍,他們不能訪問類的 this 指針。您可以使用靜態成員函數來判斷類的某些對象是否已被創建。

    靜態成員函數與普通成員函數的區別:
        靜態成員函數沒有 this 指針,只能訪問靜態成員(包括靜態成員變量和靜態成員函數)。
        普通成員函數有 this 指針,可以訪問類中的任意成員;而靜態成員函數沒有 this 指針。

下面的實例有助於更好地理解靜態成員函數的概念:
實例

#include <iostream>
 using namespace std;
 
class Box
{
   public:
      static int objectCount;
      // 構造函數定義
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // 每次創建對象時增加 1
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
      static int getCount()
      {
         return objectCount;
      }
   private:
      double length;     // 長度
      double breadth;    // 寬度
      double height;     // 高度
};
 
// 初始化類 Box 的靜態成員
int Box::objectCount = 0;
 
int main(void)
{
  
   // 在創建對象之前輸出對象的總數
   cout << "Inital Stage Count: " << Box::getCount() << endl;
 
   Box Box1(3.3, 1.2, 1.5);    // 聲明 box1
   Box Box2(8.5, 6.0, 2.0);    // 聲明 box2
 
   // 在創建對象之後輸出對象的總數
   cout << "Final Stage Count: " << Box::getCount() << endl;
 
   return 0;
}

當上面的代碼被編譯和執行時,它會產生下列結果:

Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章