C++
is a C
-based object-oriented programming language. It is
mostly compatible with C
. Some differences:
//
to end-of-line);struct somename
⇒ somename
;new
operator to allocate struct
s, class
es, etc;/* C-style variable declaration */
struct point pt;
// C++-style variable declaration
point pt2;
/* it can be achieved in C with: */
typedef struct point point;
/* C-style (still valid in C++) */
int i;
for (i = 0; i < N; ++i) {
/* actual loop code */
}
// C++-style
for (int i = 0; i < N; ++i) {
// actual loop code
}
Note: C++
source files have a .cpp
or .cc
extension.
The executable must be linked against the C++
standard
library:
gcc sourcefile.cc -o executablename -lstdc++
#include <stdio.h>
void swap(int a, int b)
{
int tmp = a;
a = b;
b = tmp;
}
int main(void)
{
int x = 1;
int y = 0;
swap(x, y);
/* nothing happened! */
printf("x=%d,y=%d\n", x, y);
}
| #include <stdio.h>
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main(void)
{
int x = 1;
int y = 0;
swap(&x, &y);
/* the values are now swapped */
printf("x=%d,y=%d\n", x, y);
}
| #include <stdio.h>
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
int main(void)
{
int x = 1;
int y = 0;
swap(x, y);
/* the values are now swapped */
printf("x=%d,y=%d\n", x, y);
}
|
|
|
|
In C
, each function has one signature. You must change the name even
when conceptually it does the same thing on different types.
#include <stdio.h>
typedef struct point2d { float x; float y; } point2d;
typedef struct point3d { float x; float y; float z;} point3d;
point2d plus2d(const point2d *pt1, const point2d *pt2) {
point2d result;
result.x = pt1->x + pt2->x;
result.y = pt1->y + pt2->y;
return result;
}
point3d plus3d(const point3d *pt1, const point3d *pt2) {
point3d result;
result.x = pt1->x + pt2->x;
result.y = pt1->y + pt2->y;
result.z = pt1->z + pt2->z;
return result;
}
int main(void) {
point2d e1_2d = { 1, 0 }, e2_2d = { 0, 1 };
point2d sum_2d = plus2d(&e1_2d, &e2_2d);
point3d e1_3d = { 1, 0, 0}, e2_3d = { 0, 1, 0 };
point3d sum_3d = plus3d(&e1_3d, &e2_3d);
printf("the 2D sum is (%f, %f)\n", sum_2d.x, sum_2d.y);
printf("the 3D sum is (%f, %f, %f)\n", sum_3d.x, sum_3d.y, sum_3d.z);
}
|
|
In C++
, you can use the same name as long as the compiler can
understand which one to use
#include <stdio.h>
struct point2d { float x; float y; };
struct point3d { float x; float y; float z;};
point2d plus(const point2d &pt1, const point2d &pt2) {
point2d result;
result.x = pt1.x + pt2.x;
result.y = pt1.y + pt2.y;
return result;
}
point3d plus(const point3d &pt1, const point3d &pt2) {
point3d result;
result.x = pt1.x + pt2.x;
result.y = pt1.y + pt2.y;
result.z = pt1.z + pt2.z;
return result;
}
int main(void) {
point2d e1_2d = { 1, 0 }, e2_2d = { 0, 1 };
point2d sum_2d = plus(e1_2d, e2_2d);
point3d e1_3d = { 1, 0, 0}, e2_3d = { 0, 1, 0 };
point3d sum_3d = plus(e1_3d, e2_3d);
printf("the 2D sum is (%f, %f)\n", sum_2d.x, sum_2d.y);
printf("the 3D sum is (%f, %f, %f)\n", sum_3d.x, sum_3d.y, sum_3d.z);
}
|
|
In C++
, you can even overload the standard operators:
#include <stdio.h>
struct point2d { float x; float y; };
struct point3d { float x; float y; float z;};
point2d operator +(const point2d &pt1, const point2d &pt2) {
point2d result;
result.x = pt1.x + pt2.x;
result.y = pt1.y + pt2.y;
return result;
}
point3d operator +(const point3d &pt1, const point3d &pt2) {
point3d result;
result.x = pt1.x + pt2.x;
result.y = pt1.y + pt2.y;
result.z = pt1.z + pt2.z;
return result;
}
int main(void) {
point2d e1_2d = { 1, 0 }, e2_2d = { 0, 1 };
point2d sum_2d = e1_2d + e2_2d;
point3d e1_3d = { 1, 0, 0}, e2_3d = { 0, 1, 0 };
point3d sum_3d = e1_3d + e2_3d;
printf("the 2D sum is (%f, %f)\n", sum_2d.x, sum_2d.y);
printf("the 3D sum is (%f, %f, %f)\n", sum_3d.x, sum_3d.y, sum_3d.z);
}
|
|
In some cases, the operations to be done are exactly the same.
In C
, you still need different function names.
#include <math.h>
/* return the biggest of the two values */
double fmax(double x, double y);
float fmaxf(float x, float y);
long double fmaxl(long double x, long double y);
/* no max() function in C for integer types */
Can we do something with macros perhaps?
#include <stdio.h>
#define MAX(a, b) ((b < a) ? a : b)
int main(void) {
int i = 1, j = 5, k = MAX(i, j);
float fi = 1.1f, fj = 2.3f, fk = MAX(fi, fj);
printf("i=%d, j=%d, k=%d\n", i, j, k);
printf("fi=%f, fj=%f, fk=%f\n", fi, fj, fk);
}
| int main(void) {
int i = 1, j = 5, k = ((j < i) ? i : j);
float fi = 1.1f, fj = 2.3f, fk = ((fj < fi) ? fi : fj);
printf("i=%d, j=%d, k=%d\n", i, j, k);
printf("fi=%f, fj=%f, fk=%f\n", fi, fj, fk);
}
|
|
Double evaluation of arguments!
#include <stdio.h>
/* DANGEROUS! Double evaluation: the biggest argument gets evaluated twice */
#define MAX(a, b) ((b < a) ? a : b)
int main(void) {
int i = 1, j = 5;
int k = MAX(++i, ++j); /* j gets incremented twice! */
printf("i=%d, j=%d, k=%d\n", i, j, k);
}
| int main(void) {
int i = 1, j = 5;
int k = ((++j < ++i) ? ++i : ++j);
printf("i=%d, j=%d, k=%d\n", i, j, k);
}
|
|
In C++
we can use templates
#include <stdio.h>
/* no double evaluation here */
template <typename T> const T& max(const T& a, const T&b) {
return (b < a) ? a : b;
}
int main(void) {
int i = 1, j = 5;
int k = max(++i, ++j); /* j only gets incremented once */
printf("i=%d, j=%d, k=%d\n", i, j, k);
}
|
|
Actually, max
is already defined in the C++
standard library, in a
slightly more complex way. It is found in the algorithm
include file,
together with a lot of other useful functions such as sort
, merge
,
etc.
We will not discuss the C++
standard library here, and only mention
a small set of the object-oriented features of C++
(CUDA has very
limited support for them).
struct
enhancements#include <stdio.h>
/* a structure collecting the physical parameters for a simulation */
struct PhysParams {
float gravity; // system gravity, in m/s^2
float density; // fluid density, in kg/m^3
float viscosity; // kinematic viscosity, in m^2/s
PhysParams() {
/* default to water on Earth */
gravity = 9.81f;
density = 1000.0f;
viscosity = 1.0e-6f;
}
};
int main(void) {
/* default */
PhysParams p1;
/* oil */
PhysParams p2;
p2.density = 920.0f;
p2.viscosity = 8.3e-5f;
printf("Parameters #1: g = %g, rho = %g, nu = %g\n",
p1.gravity, p1.density, p1.viscosity);
printf("Parameters #2: g = %g, rho = %g, nu = %g\n",
p2.gravity, p2.density, p2.viscosity);
}
|
|
#include <stdio.h>
#include <stdlib.h>
#include <new>
template <typename T>
T random_value(const T &min, const T &max) {
T rnd = T(rand())/T(RAND_MAX);
/* rnd is now a value of type T between 0 and 1 */
return (T(1) - rnd)*min + rnd*max;
}
/* a structure collecting the physical parameters for a simulation */
struct PhysParams {
float gravity, density, viscosity;
PhysParams() {
/* random fluid on Earth */
gravity = 9.81f;
density = random_value(900.0f, 2700.0f);
viscosity = random_value(0.0f, 1.0e-3f);
}
};
/* new is the equivalent of malloc + init. By default it throws an exception
but it can be used with the nothrow option to return NULL just like
malloc */
// nothrow is defined in the std namespace
using namespace std;
#define N 10
int main(void) {
PhysParams *fluid = new (nothrow) PhysParams;
PhysParams *fluidlist = new (nothrow) PhysParams[N];
if (!fluid || !fluidlist) {
fprintf(stderr, "failed to allocate fluids\n");
return 1;
}
printf("Parameters #X: g = %g, rho = %e, nu = %e\n",
fluid->gravity, fluid->density, fluid->viscosity);
for (int i=0; i < N; ++i) {
printf("Parameters #%d: g = %g, rho = %e, nu = %e\n",
i, fluidlist[i].gravity, fluidlist[i].density,
fluidlist[i].viscosity);
}
delete fluid; delete[] fluidlist;
}
|
|
C
and C++