Copy Link
Add to Bookmark
Report

C++ Newsletter/Tutorial Issue 14

eZine's profile picture
Published in 
CPPNL
 · 2 years ago

Issue #014
August, 1996

Contents

  • Notes From ANSI/ISO - String Literal Types
  • Introduction to STL Part 1 - Getting Started
  • Using C++ as a Better C Part 14 - Function-style Casts
  • Introduction to Templates Part 6 - Friends

NOTES FROM ANSI/ISO - STRING LITERAL TYPES

Jonathan Schilling, jls@sco.com

[Note: this is the first of a series of columns about the details of the ANSI/ISO C++ standardization process. Jonathan Schilling works for SCO in New Jersey and is a member of the ANSI/ISO C++ committee. You should not assume that features described in this column are available in your local C++ compiler. There is often a lag of a year or more between feature standardization and that feature showing up in an actual compiler].

At the most recent ANSI/ISO C++ standards meeting in Stockholm in July, a major change was made to the type of string literals. Previously, string literals were of type char[]; now they are of type const char[].

This repairs a longstanding blemish in C++'s type system. However, it has the potential of breaking a lot of existing code. To lessen the impact, a new standard conversion has been added to the language, from string literal to char*. (The type of wide string literals has also changed, and a similar standard conversion has been added for them).

The result is that some old code will continue to work, but some won't. For example:

    char* p = "abc";                // used to compile; still does 

char* q = expr ? "abc" : "de"; // used to compile, now an error

void f(char*);
f("abc"); // used to compile, still does

void g(char*, int);
void g(const char*, long);
g("abc", 7); // used to compile, now ambiguous

template <class T> void h(T);
template<> void h<char*>(char*);
h("abc"); // used to call specialization,
// now calls general template

try {
throw "abc";
}
catch (char*) {} // used to catch, now doesn't


The new standard conversion is immediately deprecated, meaning that it may be removed from the next revision of the standard. If that happens, the first and third examples above will become compilation errors as well.

One possibly confusing thing about this new standard conversion is that it operates upon a subset of values of a type (literal constants), rather than on all values of a type (which is more common). There is precedent, however, in existing standard conversions defined for the null pointer constant.

If you want to write code that will work under both the old and new rules, you can use just the new type in some contexts:

    const char* p = "abc"; 
const char* q = expr ? "abc" : "de";


but in some contexts requiring exact type match both types must be specified:

    try { 
throw "abc";
}
catch (char*) { /* do something */ }
catch (const char*) { /* do the same thing */ }


Changing the type of string literals is a big change in the language, which also introduces a significant new incompatibility with C. Whether the gain is worth the pain is a matter of opinion, but the ANSI vote was 80% in favor and the ISO vote was unanimous. It is expected that compiler vendors will provide a compatibility switch that gives string literals their old type.

INTRODUCTION TO STL PART 1 - GETTING STARTED

STL stands for Standard Template Library, and is a new feature of C++. We will be presenting some of the basic features of STL in this and subsequent issues. STL may not be available with your local C++ compiler as yet. The examples presented here were developed with Borland C++ 5.0. Third-party versions of STL are available from companies like ObjectSpace and Rogue Wave, and HP's original implementation (which may be obsolete) is available free on the Internet.

To get an idea of the flavor of STL, let's consider a simple example, one where we wish to create a set of integers and then shuffle them into random order:

    #include <vector> 
#include <algorithm>
#include <iostream>

using namespace std;

int main()
{
vector<int> v;

for (int i = 0; i < 25; i++)
v.push_back(i);

random_shuffle(v.begin(), v.end());

for (int j = 0; j < 25; j++)
cout << v[j] << " ";
cout << endl;

return 0;
}


When run, this program produces output like:

    6 11 9 23 18 12 17 24 20 15 4 22 10 5 1 19 13 3 14 16 0 8 21 2 7


There's quite a bit to say about this example. In the first place, STL is divided into three logical parts:

  • containers
  • iterators
  • algorithms

Containers are data structures such as vectors. They are implemented as templates, meaning that a container can hold any type of data element. In the example above, we have "vector<int>", or a vector of integers.

Iterators can be viewed as pointers to elements within a container.

Algorithms are functions (function templates actually) that operate on data in containers. Algorithms have no special knowledge of the types of data on which they operate, meaning that an algorithm is generic in its application.

We include header files for the STL features that we want to use. Note that the headers have no ".h" on them. This is a new feature in which the .h for standard headers is dropped.

The next line of interest is:

    using namespace std;


We discussed namespaces in earlier newsletter issues. This statement means that the names in namespace "std" should be made available to the program. Standard libraries use std to avoid the problem mentioned earlier where library elements (like functions or class names) conflict with names found in other libraries.

The line:

    vector<int> v;


declares a vector of integers, and then:

    for (int i = 0; i < 25; i++) 
v.push_back(i);


adds the numbers 0-24 to the vector, using the push_back() member function.

Actual shuffling is done with the line:

    random_shuffle(v.begin(), v.end());


where v.begin() and v.end() are iterator arguments that delimit the extend of the list to be shuffled.

Finally, we display the shuffled list of integers, using an overloaded operator[] on the vector:

    for (int j = 0; j < 25; j++) 
cout << v[j] << " ";
cout << endl;


This code is quite generic. For example, we could change:

    vector<int> v;


to:

    vector<float> v;


and fill the vector with floating-point numbers. The rest of the code that shuffles and displays the result would not change.

One point to note about STL performance. The library, at least the version used for these examples, is implemented as a set of header files and inline functions (templates). This structure is probably necessary for performance, due to the internal use of various helper functions (for example, begin() in the above example). Such an architecture is very fast but can cause code size blowups in some cases.

We will be saying more about STL in future issues. The library is not yet in widespread use, and it's too early to say how it will shake out.


USING C++ AS A BETTER C PART 14 - FUNCTION-STYLE CASTS

In C and C++ (and Java), you can cast one object type to another by usage like:

    double d = 12.34; 

int i = (int)d;


Casting in this way gets around type system checking. It may introduce problems such as loss of precision, but is useful in some cases.

In C++ it's possible to employ a different style of casting using a functional notation:

    double d = 12.34; 

int i = int(d);


This example achieves the same end as the previous one.

The type of a cast using this notation is limited. For example, saying:

    unsigned long*** p = unsigned long***(0);


is invalid, and would need to be replaced by:

    typedef unsigned long*** T; 

T p = T(0);


or by the old style:

    unsigned long*** p = (unsigned long***)0;


Casting using functional notation is closely tied in with constructor calls. For example:

    class A { 
public:
A();
A(int);
};

void f()
{
A a;
a = A(37);
}


causes an A object local to f() to be created via the default constructor. Then this object is assigned the result of constructing an A object with 37 as its argument. In this example there is both a cast (of sorts) and a constructor call. If we want to split hairs a perhaps more appropriate technical name for this style of casting is "explicit type conversion".

It is also possible have usage like:

    void f() 
{
int i;

i = int();
}


If this example used a class type with a default constructor, then the constructor would be called both for the declaration and the assignment. But for a fundamental type, a call like int() results in a zero value of the given type. In other words, i gets the value 0.

The reason for this feature is to support generality when templates are used. There may be a template such as:

    template <class T> class A { 
void f()
{
T t = T();
}
};


and it's desirable that the template work with any sort of type argument.

Note that there are also casts of the form "static_cast<T>" and so on, which we will discuss in a future issue.


INTRODUCTION TO TEMPLATES PART 6 - FRIENDS

In earlier issues we've seen how a template is something like a class, except that it can be parameterized, that is, type arguments can be supplied to create an actual class from a template through the process of instantiation.

In C++ friends are used to give outside functions and classes access to private members of a class. Friends can also be used with templates, in a similar way. For example:

    template <class T> class A { 
int x;
friend void f();
};

void f()
{
A<double> a;

int i = a.x;
}

int main()
{
f();

return 0;
}


In this example, the function f() gains access to the private members of all instantiated classes that come from the template A, such as A<double>, A<char**>, and so on.

In a similar way, a whole class can be granted access to private members of a template:

    template <class T> class A { 
int x;
friend class B;
};

class B {
public:
void f();
};

void B::f()
{
A<short> a;

int i = a.x;
}

int main()
{
B b;

b.f();

return 0;
}


Here, class B is a friend of template A, and so all of B's members can access the private members of A<short>.

In an earlier issue, we talked about member templates. With this feature additional combinations of friends and templates are possible.


ACKNOWLEDGEMENTS

Thanks to Steve Adamczyk, Nathan Myers, Eric Nagler, David Nelson, Terry Rudd, Jonathan Schilling, and Clay Wilson for help with proofreading.


SUBSCRIPTION INFORMATION / BACK ISSUES

To subscribe to the newsletter, send mail to majordomo@world.std.com with this line as its message body:

subscribe c_plus_plus

Back issues are available via FTP from:

rmii.com /pub2/glenm/newslett

or on the Web at:

http://www.rmii.com/~glenm

There is also a Java newsletter. To subscribe to it, say:

subscribe java_letter

using the same majordomo@world.std.com address.

-------------------------

Copyright (c) 1996 Glen McCluskey. All Rights Reserved.

This newsletter may be further distributed provided that it is copied in its entirety, including the newsletter number at the top and the copyright and contact information at the bottom.

Glen McCluskey & Associates
Professional C++ Consulting
Internet: glenm@glenmccl.com
Phone: (800) 722-1613 or (970) 490-2462
Fax: (970) 490-2463
FTP: rmii.com /pub2/glenm/newslett (for back issues)
Web: http://www.rmii.com/~glenm

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT