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)
}

 

posted @ 2021-12-21 16:01  十步一杀2017  阅读(1104)  评论(0编辑  收藏  举报