1.7 —
Forward declarations
add.cpp नाम के इस आसान से program पर एक नज़र डालिए:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <iostream>
int main()
{
using namespace std;
cout << "The sum of 3 and 4 is: " << add(3, 4) << endl;
return 0;
}
int add(int x, int y)
{
return x + y;
}
|
आप सोचेंगे की ये program result के रूप में ये देगा:
The sum of 3 and 4 is: 7
दरअसल, ये compile भी नहीं होगा! Visual Studio 2005 Express इसे compile
करते
वक़्त निम्नलिखित error देगा:
add.cpp(6) : error C3861: 'add': identifier not found
add.cpp(10) : error C2365: 'add' : redefinition; previous definition was 'formerly unknown identifier'
इस program के compile न होने का कारण है की compiler
किसी file को क्रमबद्ध रूप में पढता है
। जब compiler main के line 6 में function
call statement, add() तक पहुँचता है, इसे तब तक पता नहीं होता की
आखिर add क्या है, क्यूंकि हमने line 10
के
पहले add को define ही नही किया है! ये हमें मिले
पहले error का जवाब है (“identifier not found”) ।
जब Visual Studio 2005 line 10 में add() के वास्तविक declaration
पर
पहुँचता है, ये समझता है की add को यहाँ redefine
(दोबारा
define) किया गया है । ये थोडा अजीब है, क्यूंकि add को कभी पहले define नही किया गया था । Visual
Studio के नए versions
दूसरा
वाला error message नहीं देंगे ।
दुसरे error के बिलकुल बेकार होने के
बावजूद भी, यहाँ एक चीज़ नोट करने लायक है की किसी एक error के चलते compiler
आपको
कई और error दे सकता है, जो अकसर बिना मतलब के होते
हैं । अर्थात, यदि आप main error को सुधार लो, तो आपको बाकी errors की चिंता करने की ज़रूरत नहीं
क्यूंकि ये main error के fix होते ही अपने आप fix हो जायेंगे ।
Rule: जब आप compiler errors को fix कर रहे हों, सबसे पहले आये error को सबसे पहले fix करे
इस problem को सुलझाने के लिए, हमे इस बात को समझना होगा की compiler
अब तक add को नहीं पहचानता । तो compiler
को add के बारे में कैसे बताया जाये ? इसके दो तरीके हैं:
Option 1: add() को main() से पहले define करें:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <iostream>
int add(int x, int y)
{
return x + y;
}
int main()
{
using namespace std;
cout << "The sum of 3 and 4 is: " << add(3, 4) << endl;
return 0;
}
|
इस तरह, जब main()
add() को call करेगा,
compiler को
पहले से पता होगा की add क्या है । क्यूंकि ऊपर दिया
गया program बहुत ही छोटा है, functions को इस तरह आगे-पीछे करने का
टिका काम कर जायेगा और हमारी समस्या सुलझ जाएगी । लेकिन किसी बड़े program
में functions
को , कौन सा function
किस function
को call कर रहा है (और किस क्रम में call कर रहा है), ये खोज कर श्रेणीबद्ध करना
काफी मुश्किल हो जाता है ।
इसके अलावा, यहाँ एक और दिक्कत है । ये solution
हमेशा
कारगर साबित नहीं होगा । मान लीजिये आप एक program लिख रहे है जिनमे दो functions
A और B मौजूद हैं । यदि function
A function B को call करेगा, और function
B भी function
A को call करना चाहेगा, तो आप किसे पहले define करोगे, ताकि दोनों functions
सही से
काम करें । यदि आप A को पहले define करते हो, तो compiler
B को
नहीं समझ पायेगा । यदि आप B को पहले define करते हो, तो compiler
A को
नहीं पहचान पायेगा ।
Function prototypes और forward
declaration
Option 2: ऊपर दिए गये compiler
error को fix करने का दूसरा तरीका है forward
declaration
Forward declaration हमे compiler
को
किसी identifier को define करने से पहले ही इसके program
में
होने की सुचना देने में मदद करता है ।
Functions में, हम forward
declaration का प्रयोग कर function के body ({
और } के बीच का भाग) को लिखने से
पहले ही compiler को इस function के program
में
होने की सुचना दे सकते हैं । इस तरह से, जब compiler
function call statement को देखेगा, ये जाने बिना ही की function
असल
में करता क्या है, function को पहचान लेगा ।
किसी function का forward
declaration लिखने के लिए, हम एक declaration
statement का
प्रयोग करते हैं जिसे function prototype कहा जाता है । Function
prototype में इस
function का return type, नाम और parameters
लिखा
जाता है, पर function body नहीं (curly braces के बीच का भाग) । और क्यूंकि function
prototype एक statement
है, ये एक semicolon
के साथ
ख़त्म होता है ।
यहाँ add() function के लिए एक function
prototype लिखा
गया है:
|
1
|
int add(int x, int y); // function prototype में function का return type, नाम, parameters, और एक semicolon लिखा
जाता है । Function
body नहीं!
|
अब जो program कुछ देर पहले compile
नहीं
हुआ था, आइये देखे की add() का एक prototype
देने
के बाद इसमें क्या बदलाव आता है:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#include <iostream>
int add(int x, int y); // add() का forward declaration (एक function prototype के
द्वारा)
int main()
{
using namespace std;
cout << "The sum of 3 and 4 is: " << add(3, 4) << endl; // ये
काम करेगा क्यूंकि हमने पहले ही add() को forward declare किया है
return 0;
}
int add(int x, int y) // जबकि
add() function का body यहाँ
शुरू हुआ है
{
return x + y;
}
|
अब जब compiler main() में add() को call करने वाले statement
तक
पहुचेगा, इसे पता होगा की add() किस तरह से define किया गया है (एक function
जो दो integer
parameters लेता है और एक integer return करता है), और इसलिए ये कोई error नही देगा ।
यहाँ एक और बात ध्यान देने लायक है की function
prototypes में parameters के नाम लिखना ज़रूरी नहीं है । ऊपर दिए गये code को कुछ इस तरह से भी लिखा जा
सकता है:
|
1
|
int add(int, int);
|
फिर भी, हमारे अनुसार parameters
को नाम
देना ज्यादा बेहतर है क्यूंकि इससे आपको केवल prototype
को
देखकर ही पता चल जायेगा की parameters को कैसा नाम दिया गया है ।
अन्यथा इसके लिए आपको function के वास्तविक definition
को
देखना होगा ।
Tip: आप function
definition से copy-paste कर आसानी से function
prototype लिख सकते हैं । पर अंत में एक semicolon
देना
मत भूलना
Function body को भूल जाने पर क्या होगा
बहुत से नए programmers पूछते है की: क्या होगा यदि
हम किसी function को forward declare तो कर दे पर इसे program
में
कही भी define न करें ।
इसका जवाब है: ये निर्भर करता है । यदि एक forward
declaration लिखा गया है, पर function
कभी call नहीं किया गया तो program
बिना
कोई परेशानी के compile और run करेगा । लेकिन यदि forward
declaration लिखा गया, forward declared function को call किया गया पर इसे program
में
कही भी define नहीं किया गया है, तो program
compile तो हो
जायेगा, लेकिन linker complain करेगा की वो function
call को
नहीं समझ पा रहा है ।
इस program पर एक नज़र डाले:
|
1
2
3
4
5
6
7
8
9
10
|
#include <iostream>
int add(int x, int y); // add() का forward declaration, function prototype की सहायता से
int main()
{
using namespace std;
cout << "The sum of 3 and 4 is: " << add(3, 4) << endl;
return 0;
}
|
इस program में, हमने add() को forward
declare किया
है और इसे call भी किया है, लेकिन add() को कही भी define नहीं किया । जब हम इस program
को compile
करेंगे,
Visual Studio 2005 Express ये message देगा:
Compiling...
add.cpp
Linking...
add.obj : error LNK2001: unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z)
add.exe : fatal error LNK1120: 1 unresolved externals
जैसा की आप देख सकते हैं,
program आसानी
से compile हो गया, लेकिन ये link नहीं हो पाया क्यूंकि int
add(int, int) को कभी भी define नहीं किया गया है ।
Forward declarations के कुछ और तरीके
Forward declarations का सबसे ज्यादा प्रयोग functions
के साथ
होता है । फिर भी, forward declarations C++ के दुसरे identifiers
के साथ
भी इस्तेमाल किये जा सकते हैं, जैसे variables
और user-defined
types के साथ
। Identifiers के दुसरे प्रकार (जैसे की user-defined
types) forward declaration के लिए एक अलग syntax का इस्तेमाल करते हैं ।
आगे के एक lesson में हम देखेंगे की forward
declarations का प्रयोग दुसरे identifiers के साथ कैसे किया जा सकता है
।
Declarations vs. definitions
C++ में, आप “declaration”
और “definition”
जैसे
शब्दों का कई जगह इस्तेमाल होते हुए देखोगे । इनका मतलब क्या है ? अब आप इनके बीच के अंतर को
पहचानने लायक knowledge इकठ्ठा कर चुके हो ।
Definition असल में identifier
को implement
(काम
करने लायक बनाना) या instantiate (identifier के लिए memory
allocate करना)
करता है । नीचे definitions के कुछ उदाहरण दिए गये हैं:
|
1
2
3
4
5
6
|
int add(int x, int y) // function add() को define कर
रहा है
{
return x + y;
}
int x; // एक integer variable x को instantiate (identifier के
लिए memory allocate) कर रहा है
|
आप एक identifier के लिए केवल एक definition
लिख
सकते हो । Definition linker को संतुष्ट करने के लिए ज़रूरी है ।
Declaration एक statement
है जो
एक identifier (variable या function के नाम) और इसके type को define करता है । Declarations
के कुछ
उदहारण नीचे दिए गये हैं:
|
1
2
|
int add(int x, int y); // add नाम
के एक function का declaration जो
दो int parameters लेकर एक int value return करता
है । कोई body नही!
int x; // x नाम
के एक variable को declare करता
है
|
Declaration compiler को संतुष्ट करने के लिए काफी
है । इसलिए एक forward declaration भी compiler को खुश रखने में काफी है, जैसा की हमने कुछ ही देर पहले
देखा । लेकिन यदि आप function के definition
को
लिखना भूल गये हो, तो linker आपको error देगा ।
आप note करोगे की “int x”
दोनों
ही categories में आता है । C++ में, सभी definitions
एक तरह
से declarations भी हैं । क्यूंकि “int x” एक definition
है, by
default ये एक declaration
भी है
और यही बात और कई declarations पर भी लागु होती है ।
फिर भी, यहाँ कुछ ऐसे declarations
भी
मौजूद हैं जो definition नही हैं, जैसे की function
prototypes । इन्हें pure declarations भी कहा जाता है । Pure
declarations के कुछ और उदाहरण variables के forward
declarations, class declarations, और type declarations (आगे बढ़ते हुए आप इन सब के
बारे में जानोगे, फ़िलहाल आपको इनकी चिंता करने की जरूरत नहीं) हैं । आप एक identifier
के लिए
जितना चाहो, pure declaration लिख सकते हो (पर ये बिलकुल बेकार साबित होंगे) ।
Quiz
1) एक function
prototype और forward
declaration के बीच क्या अंतर है?
2) इस function
के लिए
prototype लिखे:
|
1
2
3
4
|
int doMath(int first, int second, int third, int fourth)
{
return first + second * third / fourth;
}
|
इनमे से हर एक program के लिए, पता करें की क्या ये compile
, link , या compile
और link दोनों होने में असफल होता है
। यदि आप sure नहीं हो, तो इन्हें compile
कर के
देखो!
3)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream>
int add(int x, int y);
int main()
{
using namespace std;
cout << "3 + 4 + 5 = " << add(3, 4, 5) << endl;
return 0;
}
int add(int x, int y)
{
return x + y;
}
|
4)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream>
int add(int x, int y);
int main()
{
using namespace std;
cout << "3 + 4 + 5 = " << add(3, 4, 5) << endl;
return 0;
}
int add(int x, int y, int z)
{
return x + y + z;
}
|
5)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream>
int add(int x, int y);
int main()
{
using namespace std;
cout << "3 + 4 + 5 = " << add(3, 4) << endl;
return 0;
}
int add(int x, int y, int z)
{
return x + y + z;
}
|
6)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream>
int add(int x, int y, int z);
int main()
{
using namespace std;
cout << "3 + 4 + 5 = " << add(3, 4, 5) << endl;
return 0;
}
int add(int x, int y, int z)
{
return x + y + z;
}
|

No comments:
Post a Comment