Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

C++ Syntax Uncovered

3.50/5 (6 votes)
17 Jul 2011CPOL7 min read 20.3K  
answers many whys in bigenners' and even advanced programmers' head about what looks strange syntax

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:

C++
void fn() {}  

if function-body-syntax were like if-statement-syntax, you would have to write it as follows: 

C++
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:

C++
...
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:

C++
...
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 
Is it is clear, now ?

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.

C++
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:

C++
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:

C++
OuterType::InnerType *someObject; 

 Actually this is only necessary when you are trying to define a template as follows:

C++
 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:  

C++
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.

C++
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:

C++
swith(input) { // asks for 
	case 'c':
	case 'C':
		cleanAllPointers(); break;
}
If things goes as in the question, code should be changed to:
C++
swith(input) { // asks for 
	case 'c':
		cleanAllPointers();
	case 'C':
		cleanAllPointers();
}
It would be very painful if the code you are about to write is too long, here is just a function call, you can imagine worse. Remember that cases are just labels, they are constant values and you cannot make complex expressions such as:
C++
case ('c' || 'C'): // this cannot be a label since
                   // labels have no spaces in their names
	cleanAllPointers();
Hence, C creators had to make the tradeoff:
  • Should we repeat the code, and stop execution, or
  • Should we save code repetition, by just repeating break;
Thanks for choosing the last choice, wise choice. Of course, you may face more complicated situations. Assume that you are reading options, if user inputs 1 you should do something_a and something_b. while if user inputs 2 you should do something_b only, now with this choice you should code it as follows:
C++
case 1:
	do_something_a;
case 2:
	do_something_b; break;
On the other hand, if switch statement breaks automatically after executing the appropriate case label, you should code it as follows:
C++
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:
C++"
cout << 3 + 4 * 2; // results in 11
This code results in 11 due to the precedence of operator* over operator+ . What will you do if you want addition to happen before multiplication? You may simply use parentheses like this:
C++
cout << (3 + 4) * 2; // results in 14
The idea is that operator() has a precedence over all other C++'s operators -except operator[] has same precedence-. Any thing in between, should be evaluated first. Back to function-pointers. Assume you want to declare a pointer to function that takes int parameter and returns char, you may code it as follows:
C++
char * ConvertAscii(int ascii); // this is a function
// returns char* not pointer to function returns char
This happens because compiler check your declaration against the following form
C++
return-type identifier(parameter-list);
Then, it finds that char* is a type. The idea is to separate char form operator*. Using parentheses allows you to mention to compiler "Hey, operator* is not part of the return-type" like this:
C++
char (*ConvertAscii)(int ascii); // this is a pointer to
// function takes int and returns char
It is normal to use a lot of explanation, to mention simple ideas .

References

  1. C++ Templates: The complete guide. By David Vandevoorde, Nicolai M. Josuttis. For typename/class question.

Other articles by author:

  1. C++ delegates part I
  2. C++ delegates part II
  3. All my future codeproject articles 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)