业精于勤荒于嬉 發表於 2025-12-15 17:58:00

Java中的final 和 C++中的final、const(C++中const关键字功能总结)

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li><mark>Java中final有三种主要用法:</mark></li><li><mark>C++中final只有两种:</mark></li><li><mark>C++中const:</mark><ul><li>修饰变量(基本类型变量、成员变量):</li><li>const与引用:</li><li>const与指针:<mark>"const在*前,数据不能改,const在*后,指针不能改"</mark></li><li>const在函数中的应用:</li><li>const修饰对象:</li></ul></li></ul></div><p></p>
<h3 id="java中final有三种主要用法"><mark>Java中final有三种主要用法:</mark></h3>
<ol>
<li>
<p><strong>修饰变量</strong>:final变量是不可改变的,但它的值可以在运行时刻初始化,也可以在编译时刻初始化,甚至可以放在构造函数中初始化,而不必在声明的时候初始化,所以下面的语句均合法:</p>
<pre><code class="language-java">final int i = 1; // 编译时刻
final int i2 = (int)(Math.Random() * 10); //运行时刻
final int i3; //构造函数里再初始化
</code></pre>
<p>final经常和static一起用,这种用法类似C++的常量,在Java中很常见,比如 <code>static final i = 10; </code>但这里同样也是允许运行时刻初始化的。</p>
</li>
<li>
<p><strong>修饰类对象</strong>:而如果修饰类对象,并不表示这个对象不可更改,而是表示这个这个变量不可再赋成其它对象,这就比较像 C++的 <code>Class const * p</code>了(这样表明这个指向该Class的指针p不能再指向其他对象,<strong>指针常量</strong>,但是该对象中的值是可以修改的(<code>const Class *p</code> 是<strong>常量指针</strong>,任何成员变量都不能修改))。</p>
<pre><code class="language-java">final Value v = new Value();
v = new Value(); //不允许!
v.some_method(); //允许
</code></pre>
</li>
<li>
<p><strong>修饰方法:</strong>final修饰的方法是不能被重载的,类似于类中的private方法,所以private方法默认是final的;大致说就是变量不可修改(基本数据类型值不能修改,类类型引用不能修改),方法不可重载,类不可继承,</p>
</li>
</ol>
<h3 id="c中final只有两种"><mark>C++中final只有两种:</mark></h3>
<ol>
<li>
<p>修饰类</p>
</li>
<li>
<p>修饰虚函数</p>
</li>
</ol>
<h3 id="c中const"><mark>C++中const:</mark></h3>
<p>C++中的const用处很多,包括常量声明、变量修饰、常量引用、指针与const的组合、以及常量对象、成员函数。</p>
<h4 id="修饰变量基本类型变量成员变量">修饰变量(基本类型变量、成员变量):</h4>
<ul>
<li>
<p>修饰基本类型变量</p>
<p>修饰变量也可以叫作常量的声明,使用<code>const</code>关键字可以修饰变量,一旦初始化后就不能再修改其值。</p>
<pre><code class="language-c++">const int MAX = 123;
const double PI = 3.14;
const int x = 334;
</code></pre>
<p>以上的MAX、PI、x将都不能再修改其值;</p>
<p><code>const</code>定义的常量和<code>#define</code>宏定义的常量的区别</p>
<blockquote>
<p>const常量有数据类型,define宏定义常量没有,编译器会对const常量可以进行数据类型的安全检查,但是对于define宏定义,编译器只是将其进行字符替换,这样的字符替换很容易出错。</p>
<p>比如以下代码,如果使用不加括号的宏定义,将不能正确计算(a+b)/5.0,而是变成计算a+(b/5.0)了。</p>
<pre><code class="language-cpp">//define宏定义的做法
#define a 2.0
#define b 9.0
#define c1 a+b   //不好的定义方法
#define c2 ((a)+(b))//推荐的定义方法
void func1(void)
{
    float d1 = c1/5.0;//本意是想计算(a+b)/5.0,但字符替换使计算变成了a+b/5.0
    float d2 = c2/5.0;//正确计算了((a)+(b))/5.0 = (a+b)/5.0
}


//推荐的const常量的做法
const float a = 2.0;
const float b = 9.0;
const float c = a + b;
void func2(void)
{
    float d = c/5.0;//正确计算了(a+b)/5.0
}
</code></pre>
</blockquote>
</li>
<li>
<p>修饰成员变量:在类中,使用<code>const</code>修饰的成员变量只能在初始化列表中进行初始化,并且不能在构造函数中修改其值。</p>
<pre><code class="language-c++">class MyClass {
public:
    const int x;
    MyClass(int value) : x(value) {} // 初始化const修饰的成员变量
};
</code></pre>
<p>这段代码定义了一个类<code>MyClass</code>,其中有一个const修饰的整型成员变量<code>x</code>。在构造函数的初始化列表中对<code>x</code>进行初始化,且只能在初始化列表中初始化,不能在构造函数内部修改其值。</p>
</li>
</ul>
<h4 id="const与引用">const与引用:</h4>
<p>const引用可以绑定到临时对象或字面量,延长其生命周期。</p>
<p>用这种方式声明的引用,<strong>不能通过引用对目标变量的值进行修改</strong>,从而使引用的目标成为const,达到了引用的安全性。</p>
<pre><code class="language-C++">const int&amp; ref = 10; // 合法
// int&amp; ref2 = 10;   // 非法:非常量引用不能绑定字面量
int x = 10;
const int&amp; a = x;
x = 5;
</code></pre>
<h4 id="const与指针const在前数据不能改const在后指针不能改">const与指针:<mark>"const在*前,数据不能改,const在*后,指针不能改"</mark></h4>
<ul>
<li>
<p>常量指针:</p>
<p>形式:<code>const type* ptr</code>(推荐) 或 <code>type const* ptr</code></p>
<p>这里可以理解为 const修饰的是type类型的数据:(const type)* ptr 或 (type const)* ptr,也就是说不能通过ptr修改值,但ptr可以指向其他地址。</p>
<pre><code class="language-c++">int a = 10, b = 20;
const int* ptr = &amp;a;
*ptr = 30; // 错误:不能修改指向的数据
ptr = &amp;b;// 正确:可以改变指针指向
</code></pre>
<p><strong>"const在*前,数据不能改"</strong></p>
</li>
<li>
<p>指针常量:</p>
<p>形式:<code>type* const ptr</code></p>
<p>这里可以理解为const修饰的是ptr:也就是说ptr一旦初始化指向之后就不能指向其他地址,但可以通过指针修改所指向的数据。</p>
<pre><code class="language-c++">int a = 10, b = 20;
int* const ptr = &amp;a;
*ptr = 30; // 正确:可以修改a的值
ptr = &amp;b;// 错误:不能改变指针指向
</code></pre>
<p><strong>"const在*后,指针不能改"</strong></p>
</li>
<li>
<p>指向常量 的 常量指针:</p>
<p>形式:<code>const type* const ptr</code> 或<code>type const* const ptr</code></p>
<p>既不能修改指针指向,也不能通过指针修改数据。</p>
<pre><code class="language-c++">int a = 10, b = 20;
const int* const ptr = &amp;a;
*ptr = 30; // 错误
ptr = &amp;b;// 错误
</code></pre>
</li>
</ul>
<h4 id="const在函数中的应用">const在函数中的应用:</h4>
<ul>
<li>
<p>const形参:避免函数内意外修改参数,常用于指针或引用传参。</p>
<pre><code class="language-c++">void print(const int* arr, int size) {
    for (int i = 0; i &lt; size; ++i)
      std::cout &lt;&lt; arr &lt;&lt; " "; // 只读访问
}
</code></pre>
</li>
<li>
<p>const成员函数:const修饰类成员函数,实际修饰该成员函数隐含的<strong>this指针</strong>,表明在该成员函数中不能对类的任何成员进行修改。</p>
<pre><code class="language-C++">class MyClass {
    int value;
public:
    int getValue() const { return value; } // 不会修改对象状态
};
</code></pre>
</li>
<li>
<p>const返回值:也是用const来修饰返回的指针或引用,保护指针指向的内容或引用的内容不被修改,也常用于运算符重载。</p>
<p>函数三种返回类型:返回值、返回引用(&amp;)、返回指针(*);</p>
<ul>
<li>
<p>返回值:</p>
<p>现在返回值使用const几乎没有意义,例如:</p>
<pre><code class="language-c++">const int ten(){
    return 10; //返回值是一个临时对象
}

//在后续的赋值中
const int x = ten();
</code></pre>
<p>在c++11之后,临时对象本来就不能被修改,所以 <code>const int ten()</code>和<code>int ten()</code>本质上效果一样。</p>
</li>
<li>
<p>返回引用或者指针(这里用引用举例,指针一样的道理):</p>
<p>引用返回值不是重新创建一个对象,而是直接把函数内部(或外部某处)的对象引用返回给调用者;</p>
<p>这样将不会产生对象拷贝(性能高),调用者直接访问的就是原对象。</p>
<p>给引用加<code>const</code>可以保护原对象不被调用者修改,例如:</p>
<pre><code class="language-c++">class A {
public:
        int&amp; getValue2(){
                return m_value;
        }
        const int&amp; getValue(){
                return m_value;
        }
private:
        int m_value = 10;
};

int main() {
        A a;
        a.getValue() = 100;   //不允许修改
        a.getValue2() = 111;//直接修改成员
}
</code></pre>
<p>getValue()将不允许修改成员变量m_value,而getValue2()将会直接修改成员变量m_value;</p>
<p>一般get函数会被const修饰<code>const int&amp; getValue const(){return m_value}</code>这样函数内的成员变量也会被const修饰,不允许修改。</p>
<p>在返回const引用要<strong>注意:返回对象的生命周期必须比函数长</strong>,例如:</p>
<pre><code class="language-c++">const int&amp; backNum() {
        int num = 1;
        return num;    //错误:num会在函数结束后消失,这块内存的位置也会给其他变量用
}
void otherFunc() {
        int a = 100;
        int b = 200;
}
int main() {

        const int&amp; c = backNum();
        otherFunc();
        cout &lt;&lt; c &lt;&lt; endl;
}
</code></pre>
<p>这样的引用指向在程序复杂的时候会造成悬空引用,未定义行为等危险。</p>
</li>
</ul>
</li>
</ul>
<h4 id="const修饰对象">const修饰对象:</h4>
<p>const修饰的对象,其成员变量都不能被修改。</p>
<pre><code class="language-c++">class MyClass {
public:
    int x;
};

const MyClass obj; // 常量对象
// obj.x = 10; // 错误,常量对象的成员变量不能被修改
</code></pre><br><br>
来源:https://www.cnblogs.com/ggkx/p/19353959
頁: [1]
查看完整版本: Java中的final 和 C++中的final、const(C++中const关键字功能总结)