C++ (*, &, const, ::) 的一般意義和用法


0 引言


 《C和指針》中對&操作符,*操作符和const修飾詞有一些基本的介紹,這些介紹精確戳中了其本質含義,對於涉及到這些操作符的語法的理解很有幫助。因此寫作這篇博文幫助后續的理解。

reference:

  • 《C和指針》
  • https://stackoverflow.com/questions/3141087/what-is-meant-with-const-at-end-of-function-declaration
  • https://www.cnblogs.com/ghjnwk/p/15555186.html  
  • http://www.mathcs.emory.edu/~cheung/Courses/561/Syllabus/3-C/ref-deref.html  reference and dereference 
  • http://duramecho.com/ComputerInformation/WhyHowCppConst.html
  • https://stackoverflow.com/questions/751681/meaning-of-const-last-in-a-function-declaration-of-a-class

1 基本含義


 (1)&操作符 (reference operator) and also (address of operator):

reference operator & operates on a (single) variable name and return the address of  that variable.

&操作符產生他的操作數的地址。通常用於兩個地方:

  • 引用聲明: 在引用聲明中,& 不應當被理解為取地址,而應當和變量類型int一起被看作是一個整型引用。

  int i = 17;

  int& r = i; ///< 意義: r 是一個初始化為 i 的整型引用

  • 給指針賦值

  int *a;

  int b = 100;

  a = &b;

(2)*操作符(dereference operator): the dereference operator * operates on an address (an unsigned integer) and return the value stored at that address.

  聲明一個指針的含義如下:對 int   *a; 來說,這條語句表示表達式 *a產生的結果類型是int. 知道了*操作符執行的是間接訪問操作之后,我們可以推斷a肯定是一個指向int的指針。 eg:

  • int *b, c, d;    ///< 聲明一個整型指針變量b和兩個整型變量c, d
  • int *b, *c, *d; ///< 聲明三個整型的指針變量
  • char *message = "hello world";  ///< 這條語句把message聲明為一個指向字符的指針,並用字符串常量中第一個字符的地址對該指針進行初始化。  等價於以下:
  • char  *message;  message = "hello world";

  初始化一個指針變量的基本方法

  • int *a = &b;
  • std::cout << "int value at address 136760 = " << *(int* ) 136760 << std::endl;  ///< (type* ) tells compiler how much memory need to be allocated.  

(3)const修飾詞和*指針

  • int const a = 15;  equals  const int a = 15;  目前選擇const int a = 15; 作為本人的常用形式
  • const int  *pci;  ///< 含義: pci是一個指針,當解引用(*)pci時,得到一個const int類型的值,表明pci是一個指向const int的指針。
  • const int   *const pci;  ///< 含義: pci是一個指針,當解引用(*)pci時,得到一個const int 類型的值,表明pci是一個指向const int的指針。同時,pci被const修飾,因此pci本身的值和它指向的那個值都不能被修改。
  • #define 和const:  #define指令是另一種創建名字變量的機制。 例子:
    • #define MAX_ELEMENTS 50
    • const int max_element = 50;

      在這種情況下, 使用#define比使用const變量更好。因為只要允許使用字面值變量的地方都可以使用前者,比如聲明數組長度。而const變量只能用於允許使用變量的地方。

2 常量引用的基本規則以及 (const Var&, Var is a class name)


    基本規則1:如果一個普通函數的參數是一個const reference object,那么它將只能夠調用被const修飾的類成員函數.  eg:

#include <iostream>

class Var {
    public:
        Var(const int &size) { d_size = size; }
        int getSize() { return d_size; }

    private:
        int d_size;
};

void noChangeSize(const Var &aa) {
    std::cout << "aa.size = " << aa.getSize() << std::endl;
}

void TestConstRef()
{
    Var aa(77);
    std::cout << "aa.size = " << aa.getSize() << std::endl;
    noChangeSize(aa);
}

int main() {
    TestConstRef();
    return 0;
}

  compiling output:

test.cpp: In function ‘void noChangeSize(const Var&)’:
test.cpp:15:45: error: passing ‘const Var’ as ‘this’ argument of ‘int Var::getSize()’ discards qualifiers [-fpermissive]
     std::cout << "aa.size = " << aa.getSize() << std::endl;

    下面將另起一章介紹const修飾函數

3 用const修飾函數


examples:

///< case1: const at the beginning
const int MyClass::showName(string id){
...
}

///< case2: const at the end
int MyClass::showName(string id) const{
...
}

///< case3: const both at the beginning and at the end
const int MyClass::showName(string id) const{
...
}

  

(1)const 在函數的名字前面

  在case1中,表示MyClass::showName的返回值是一個const int類型的值。此時有兩種調用方式

  • const int id = m.showName("id");   ///< 在這種情況下,被從返回值copy過來的時候,id被初始化為跟返回值一樣的類型,不能被修改
  • int id = m.showName("id");             ///< 在這種情況下,id被一個const int 類型的返回值初始化為int類型,此時當然可以被修改

  

(2)const 在函數的尾巴那里

  在case2中,表示MyClass::showName在操作MyClass的類成員變量是,不應該對其中的變量進行修改。 此處case2的寫法相當於傳給showName一個const類型的this指針。寫作如下:

  • case2 equals  
    int MyClass::showName(const MyClass *this, string id) const{
      ...///< class member of this should not be changed by this function.
    }

  但是也有例外的情形,當class member被mutable修飾的時候,是可以被以const結尾修飾的function修改值的

#include <iostream>

class Var {
    public:
        Var(const int &size) { d_size = size; }
        int getSize() { return d_size; }
        void setSize(const int& size) const { d_size = size; }

    private:
       mutable int d_size;
};

void noChangeSize(Var* aa) {
    aa->setSize(89); ///< not supported.
    std::cout << "aa.size = " << aa->getSize() << std::endl;
}

void TestConstRef()
{
    Var aa(77);
    std::cout << "aa.size = " << aa.getSize() << std::endl;
    noChangeSize(&aa);
}

int main() {
    TestConstRef();
    return 0;
}

 

4 ::


 (1) :: is known as the scope resolution operator.  eg: 

a. std::cout ,    std::cin  are defined within std , so they have to qualify their names with   std::

b. foo::foo() {};  class is similar as namespace, 用法類似。

(2) :: is used to dereference scopes.

const int x = 5;

namespace foo {
  const int x = 0;
}

int bar() {
  int x = 1;
  return x;
}

struct Meh {
  static const int x = 2;
}

int main() {
  std::cout << x; // => 5
  {
    int x = 4;
    std::cout << x; // => 4
    std::cout << ::x; // => 5, this one looks for x outside the current scope
  }
  std::cout << Meh::x; // => 2, use the definition of x inside the scope of Meh
  std::cout << foo::x; // => 0, use the definition of x inside foo
  std::cout << bar(); // => 1, use the definition of x inside bar (returned by bar)
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM