C++ Syntax Uncovered
Jul 17, 2011
7 min read
C++
C++/CLI
C
C#
Java

by Mohammad Nasim
Contributor
Introduction
Some beginner programmers think of C++ syntax as worthless, in this article you are going to learn how it is very logical to keep things as it is. This article may be applied to both C# and JAVA as their syntax is similar to C++ syntax.
The best form to introduce this syntactic logic is via Q/A form, lets start.
Acknowledgment
I wanna thank Andrew Phillips for his contribution helping me fix some facts about switch statement.C++ Syntax Uncovered:
Why C++ binds a programmer to use braces with function definition, although it may contain one simple statement in its body? In other words why function-body does require braces while if-statement body doesn't ?
Assume you have an empty function-body, How should you type it?!! In C++ syntax, you should write it as follows:
void fn() {}
if function-body-syntax were like if-statement-syntax, you would have to write it as follows:
void fn();
The semicolon is necessary, to tell compiler the end of statement. This is the case with for-loop-statement empty body, and if-statement empty body. But if you think as a compiler, you will get confused; Is this empty function-body or just a prototype? or if a compiler finds this statement inside a class-definition how should compiler behave? if it is an empty function, compiler should generate inline code once it finds a call for this function, while if it is a prototype, compiler should look for a definition somewhere and it should generate a normal-function-call once it finds a call for this function. Another scenario, should a compiler treat this class as abstract-class because of absence of definition of this function (this is a prototype), or it is a concrete class because of existence of function-definition?!!(no no no this is not a prototype). Actually just thinking about ambiguity between function-definition and function-prototype is painful. I think that I have introduced enough headache.
Why there are such braces with try-catch blocks?
First, lets talk about try-block. As both try and catch are both connected, we treat them as a single statement, i.e the existence of one of them with absence of the other is nonsense. Also, you have to recall that one try-block can have more than one catch-blocks to handle multiple exceptions of different types correctly. Now assume you have the following code:
...
try { // if this brace is not exist, ..... read next comment
...
try {
...
}
catch(except &e1) {
...
}
catch(except &e2) { // is this the 2nd catch for 2nd
//try, or 1st catch for 1st try
... // only the above brace can resolve this ambiguity
}
...
} // thank you brace, now I know that the previous two catch
// statements are for the nested try-block
I think code explains itself. Again, just think as a compiler and you will find yourself confused because the code would be ambiguous if braces are not there. Second, catch-block, hmmm just check out the following code:
...
try {
...
}
catch(except &e1) { // if this brace is not exist, .......
// read the following comment
...
try {
...
}
catch(except &e2) {
...
}
catch(except &e3) { // is this 2nd catch for 2nd try, or 2nd
// catch for 1st try???
... // only the above brace can resolve this ambiguity
}
} // thank you brace, now I know that the previous two catch
//statements are for nested try-block
Why we need typename keyword, while class keyword replace it ?
Actually, class keyword does not replace typename keyword everywhere. It does in template definition only.
template <class T>
T fn(){}
template <typename T>
T fn(){}
There are many cases where you must use typename keyword. I will mention only one. Assume you have an outer class containing a struct or class inside it (composition, not inheritance). Now, assume you want to declare/define a pointer to an object of this nested type, How should you code this? You may code this as follows:
OuterType::InnerType *someObject;
But, have you thought as a compiler when you read this line? If so, you should get confused. Is this an expression trying to multiply someObject by a static data member InnerType ? or is this a declaration of pointer of type InnerType ? Recall, when you have a static data member, you can call it by typing out class name followed by the address-resolution-operator:: followed by the member-name. To solve this ambiguity, you have to use typename keyword, as follows:
OuterType::InnerType *someObject;
Actually this is only necessary when you are trying to define a template as follows:
template <typename OuterType>
void foo() {
typename OuterType::InnerType *innerPtr;
// do something with this pointer
}
David Vandevoorde, Nicolai M. Josuttis in their valuable book C++ Templates: The Complete Guide have mentioned about four positions in which you have to use typename. I think this code is enough to show the need of this keyword. I am not going to explain templates in depth.
Why class-type definition requires ending semicolon, while function definition does not?
Well, class-type definition is mainly used to define an object of its type (i know that it may an abstract class, but i talk in general), hence the semicolon to end the statement of declaration. In other words, braces in class-definition mean the start and end of the block that defines the size of the object being allocated in the RAM, but not the end of declaration statement. Have you ever seen a code like this:
class Person {
public:
string name;
int age;
bool male;
....
}per; // NOTICE: declaration seen here
As you can see, braces here to show the block bounds, so that we can determine the size of this data type, but the declaration has not ended yet, it show object's name after the end brace 'per' followed by semicolon to tell the end of declaration statement. When you omit the object name, compiler simply understands that you don't need declaration now. Functions don't need this, because it is not expected to be used to declare something. Another scenario that is urgent for semicolon to be used, is anonymous class-types. They are class/struct/union that has no name, only body and conceptually there must be a declaration.
struct {
int a;
bool b;
}var1;
Why does switch statement require break; after each case ? In other words, why doesn't execution stop after the appropriate case ?
Actually, this is very useful not as you think. In some cases programmer wants to execute one piece of code if more than one condition happens. For example, assume you have a menu of options and you read input:
swith(input) { // asks for
case 'c':
case 'C':
cleanAllPointers(); break;
}
swith(input) { // asks for
case 'c':
cleanAllPointers();
case 'C':
cleanAllPointers();
}
case ('c' || 'C'): // this cannot be a label since
// labels have no spaces in their names
cleanAllPointers();
- Should we repeat the code, and stop execution, or
- Should we save code repetition, by just repeating break;
case 1:
do_something_a;
case 2:
do_something_b; break;
case 1:
do_something_a; do_something_b;
case 2:
do_something_b;
I am not going to say imagine if something_b were a complicated code; I just say imagine if something_b is just a simple try/catch block, what would code look like ? so long!
Why function-pointers require too many parentheses?!
Looks hard question, but in fact, it has the shortest answer in this article. The answer is "Revise C++ Precedence Table". That is it. Lets explain more. Examine the following trivial code:cout << 3 + 4 * 2; // results in 11
cout << (3 + 4) * 2; // results in 14
char * ConvertAscii(int ascii); // this is a function
// returns char* not pointer to function returns char
return-type identifier(parameter-list);
char (*ConvertAscii)(int ascii); // this is a pointer to
// function takes int and returns char
References
- C++ Templates: The complete guide. By David Vandevoorde, Nicolai M. Josuttis. For typename/class question.
Other articles by author:
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)