کلمه‌ی کلیدی final و الگوریتم‌های آرایه در ++C

C Plus Plus Final Specifier

19 اردیبهشت 1401
C++-final-specifier

در جاوا، می‌توان از final برای یک تابع که تضمین کند که آن تابع نمی‌تواند بازنویسی یا  overridden شود، استفاد کرد. همچنین در جاوا برای تضمین این‌که یک کلاس نمی‌تواند ارث‌برده شود، از final استفاده می‌شود. به طور مشابه، آخرین استاندارد ++C که  C++ 11 است، final را اضافه کرده است.

استفاده از مشخصه‌ی final در 11++C:

گاهی اوقات نمی‌خواهید به کلاس مشتق‌شده امکان بازنویسی تابع مجازی کلاس پایه را بدهید. 11++C این امکان را به راحتی و ذاتا برای جلوگیری از بازنویسی تابع مجازی با استفاده از مشخصه‌ی final می‌دهد.

قطعه‌کُد زیر را که استفاده از مشخصه‌ی final را به نشان می‌دهد، در نظر بگیرید. این برنامه کامپایل نمی‌شود:

#include <iostream>
using namespace std;
 
class Base
{
public:
    virtual void myfun() final
    {
        cout << "myfun() in Base";
    }
};
class Derived : public Base
{
    void myfun()
    {
        cout << "myfun() in Derived\n";
    }
};
 
int main()
{
    Derived d;
    Base &b = d;
    b.myfun();
    return 0;
}

خروجی قطعه‌کُد بالا به این صورت است:

prog.cpp:14:10: error: virtual function ‘virtual void Derived::myfun()’
     void myfun()
          ^
prog.cpp:7:18: error: overriding final function ‘virtual void Base::myfun()’
     virtual void myfun() final

دومین استفاده از مشخصه‌ی final:

مشخصه‌ی final در 11++C می‌تواند برای جلوگیری از ارث‌بری از کلاس یا ساختار نیز استفاده شود. اگر یک کلاس یا یک ساختار final شود، غیر‌قابل ارث‌بری می‌شود و نمی‌توانند به عنوان ساختار یا کلاس پایه استفاده شوند.

قطعه‌کُد زیر استفاده از مشخصه‌ی final برای غیر‌قابل ارث‌بری کردن کلاس را نشان می‌دهد:

#include <iostream>
class Base final
{
};
 
class Derived : public Base
{
};
 
int main()
{
    Derived d;
    return 0;
}

خروجی قطعه‌کُد بالا به این صورت است:

error: cannot derive from ‘final’ base ‘Base’ in derived type ‘Derived’
 class Derived : public Base

final در 11++C درمقابل جاوا

توجه کنید که استفاده از مشخصه‌ی final در 11++C شبیه به جاوا است، اما جاوا از final قبل از نام کلاس استفاده می‌کند، درحالی که مشخصه‌ی final بعد از نام کلاس در 11++C استفاده می‌شود. به همین ترتیب، جاوا از کلمه‌ی کلیدی final در ابتدای تعریف متُد (قبل از نوع برگشتی متُد) استفاده می‌کند، اما در 11++C مشخصه‌ی final بعد از نام تابع استفاده می‌شود:

class Test
{
    final void fun()// use of final in Java
    { }
}
class Test
{
public:
    virtual void fun() final //use of final in C++ 11
    {}
};

برخلاف جاوا، final یک کلمه‌ی کلیدی در 11++C نیست. final تنها زمانی که در زمینه‌ی بالا استفاده شود، معنا دارد، درغیراینصورت فقط یک شناسه است. یک دلیل احتمالی که final یک کلمه‌ی کلیدی نیست، تضمین انطباق‌پذیری به عقبه است. شاید تولید کد‌هایی که از final برای اهداف دیگر استفاده می‌کند وجود دارد. برای مثال قطعه‌کُد زیر بدون خطایی کامپایل و اجرا می‌شود:

#include <iostream>
using namespace std;
 
int main()
{
    int final = 20;
    cout << final;
    return 0;
}

خروجی قطعه‌کُد بالا به این صورت است:

20

در جاوا، final نیز می‌تواند با متغیر‌های استفاده شود تا تضمین کند که مقدار تنها یک‌بار می‌تواند اختصاص داده شود. این استفاده از final در 11++C وجود ندارد.

الگوریتم‌های آرایه در کتابخانه‌ی STL

از ++C به بعد، الگوریتم‌های جدید و جالی در کتابخانه‌ی STL در ++C افزوده‌ شده‌اند. این الگوریتم‌ها روی یک آرایه عمل می‌کنند و در صرفه‌جویی زمان در طی مدت کد‌نویسی مفید هستند و بنابراین در برنامه‌نویسی رقابتی هم مفید هستند.

الگوریتم ()all_of

این تابع روی طیف کامل عناصر آرایه عمل می‌کند و می‌تواند در زمان اجرای یک حلقه برای بررسی هر عنصر به صورت تک به تک صرفه‌جویی کند. این تابع  یک ویژگی داده‌شده روی هر عنصر را بررسی می‌کند و زمانی که هر عنصر در طیف با ویژگی مشخص‌شده موافقت کند، true برگشت داده می‌شود، درغیر اینصورت fals برگشت داده می‌شود.

// C++ code to demonstrate working of all_of()
#include<iostream>
#include<algorithm> // for all_of()
using namespace std;
int main()
{
    // Initializing array
    int ar[6] =  {1, 2, 3, 4, 5, -6};
  
    // Checking if all elements are positive
    all_of(ar, ar+6, [](int x) { return x>0; })?
          cout << "All are positive elements" :
          cout << "All are not positive elements";
  
    return 0;
  
}

خروجی قطعه‌کُد بالا به این صورت است:

All are not positive elements

در قطعه‌کُد بالا، -6 یک عنصر منفی بوده است که شرط را نقض و false را برگشت می‌دهد.

الگوریتم ()any_of

این تابع یک طیف داده‌شده را بررسی می‌کند اگر حتی یک عنصر موافق با ويژگی اشاره‌شده در تابع وجود داشته باشد،‌ چنانچه دست‌کم یک عنصر با ویژگی موافق باشد true و در غیر اینصورت false برگشت داده می‌شود.

// C++ code to demonstrate working of any_of()
#include<iostream>
#include<algorithm> // for any_of()
using namespace std;
int main()
{
    // Initializing array
    int ar[6] =  {1, 2, 3, 4, 5, -6};
  
    // Checking if any element is negative
    any_of(ar, ar+6, [](int x){ return x<0; })?
          cout << "There exists a negative element" :
          cout << "All are positive elements";
  
    return 0;
  
}

خروجی قطعه‌کُد بالا به این صورت است:

There exists a negative element

الگوریتم ()none_of

این تابع اگر هیچ یک از عناصر با شرط فراهم‌شده موافق باشد، true و در غیر اینصورت false را برگشت می‌دهد.

// C++ code to demonstrate working of none_of()
#include<iostream>
#include<algorithm> // for none_of()
using namespace std;
int main()
{
    // Initializing array
    int ar[6] =  {1, 2, 3, 4, 5, 6};
  
    // Checking if no element is negative
    none_of(ar, ar+6, [](int x){ return x<0; })?
          cout << "No negative elements" :
          cout << "There are negative elements";
  
    return 0;
}

خروجی قطعه‌کُد بالا به این صورت است:

No negative elements

از آنجایی که همه‌ی عناصر مثبت هستند، تابع true را برگشت می‌دهد.

الگوریتم ()copy_n

تابع ()copy_n عناصر یک آرایه به آرایه جدید کپی می‌کند. این نوع از کپی یک deep copy از آرایه ایجاد می‌کند. این تابع 3 آرگومانت دریافت می‌کند، نام آرایه منبع، اندازه‌ی آرایه و نام آرایه هدف.

// C++ code to demonstrate working of copy_n()
#include<iostream>
#include<algorithm> // for copy_n()
using namespace std;
int main()
{
    // Initializing array
    int ar[6] =  {1, 2, 3, 4, 5, 6};
  
    // Declaring second array
    int ar1[6];
  
    // Using copy_n() to copy contents
    copy_n(ar, 6, ar1);
  
    // Displaying the copied array
    cout << "The new array after copying is : ";
    for (int i=0; i<6 ; i++)
       cout << ar1[i] << " ";
  
    return 0;
  
}

خروجی قطعه‌کُد بالا به این صورت است:

The new array after copying is : 1 2 3 4 5 6

در قطعه‌کُد بالا، عناصر ar در ar1 با استفاده از ()copy_n کپی‌شده‌اند.

الگوریتم ()iota

این تابع برای اختصاص مقادیر پیوسته به آرایه استفاده می‌شود که 3 آرگومانت را قبول می‌کند. نام آرایه، اندازه و عدد شروع.

// C++ code to demonstrate working of iota()
#include<iostream>
#include<numeric> // for iota()
using namespace std;
int main()
{
    // Initializing array with 0 values
    int ar[6] =  {0};
  
    // Using iota() to assign values
    iota(ar, ar+6, 20);
  
    // Displaying the new array
    cout << "The new array after assigning values is : ";
    for (int i=0; i<6 ; i++)
       cout << ar[i] << " ";
  
    return 0;
  
}

خروجی قطعه‌کُد بالا به این صورت است:

The new array after assigning values is : 20 21 22 23 24 25

در قطعه‌کد بالا، مقادیر پیوسه با استفاده از ()iota به آرایه اختصاص داده شده است.


منابع: Array algorithms in C++ STL، Final Keyword

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.