C++
From charlesreid1
http://www.codeguru.com/forum/showthread.php?t=
Building C++ Programs
Building on the Command-Line
The Hello World page has an example of a simple "hello world" program in C++. You can also visit the page for the 2010 Scientific Computing Summer Workshop page and view the second workshop, which is on creating and building scientific software.
Building via Makefiles
The Make page has an example of how to build a more complex program in C++ using a Makefile to automate the process. Also, as mentioned above, you can visit the 2010 Scientific Computing Summer Workshop page. The second workshop also covers Makefiles.
Building via CMake
Building via Autotools
C++ Libraries
C++ libraries provide a method of encapsulating C++ code and objects, so that they can be used by other programs. Many scientific software packages, such as Hypre or Petsc, provide library interfaces. An example of how to encapsulate C++ code is given below.
Simple library example
(Also see the Scientific Computing Summer Workshop 2.)
This example will show how to encapsulate code for a single C++ class, A
.
Creating the library
The directory structure for the library project is as follows:
src/
|
Source code (.cc) |
include/
|
Include/header files (.h) |
lib/
|
Contains libraries (which we will create) |
The code for the project is:
include/A.h
|
src/A.cc
|
---|---|
class A { public: A( int x ); ~A(); void echo(); private: int x_; }; |
#include <A.h> #include <iostream> A::A( int x ) : x_(x) {} A::~A() {}; void A::echo() { std::cout << "x = " << x_ << "\n"; } |
To begin, the class A must be compiled into an object file, but not compiled into an executable (since there's no main()
function). To compile code into an object file without creating an executable, use the -c
flag for gcc:
$ g++ -g -c src/A.cc -Iinclude/
The -I/path/to/header/files
compiler flag tells the compiler where to find the header files that were included using #include "headerfile.h"
.
After A is compiled into an object file, create a library from A.o
using the ar
Unix utility, call it libclassA
, and put it in the lib/
directory:
$ ar rs lib/libclassA.a A.o
(see the ar
man page at http://linux.die.net/man/1/ar)
NOTE: The naming scheme for libraries consists of the prefix "lib" followed by the library name of your choosing (in this case, classA).
Using the library
Compiling a driver that utilizes the library requires a few things:
- The header file for class A (but the source code file
A.cc
is not required) - The compiler must be pointed to the header file location using
-I/path/to/header/files
- The compiler must be pointed to the library locations using
-L/path/to/library/files
- The library file
libclassA.a
; the compiler must be pointed to this library file using-lclassA
A driver that uses class A is given below:
src/Driver.cc
|
---|
#include <A.h>
#include <iostream>
int main()
{
A* obj = new A( 5 );
obj->echo();
delete obj;
}
|
This driver may be compiled with g++
like this:
$ g++ src/Driver.cc -o Driver.x -Iinclude/ -Llib/ -lclassA
Some important things to notice:
- You still need the header file to use class A
- The source code for class A,
A.cc
, is not used anywhere.
Pulling apart libraries
(this is some gdb command... need to dig up the link I found to explore this stuff... had LOTS of interesting info)
C++ Object-Oriented Stuff
The following is a list of random stuff about C++ objects that I tend to forget, and end up writing little test objects to ensure I get it right.
Inheritance
(need to dig up some of the stuff here... like, if you redefine a method in the child class, and you create a base class pointer to a child class instance, does it run the child class version of the method?)
(and, a derived class runs the parent class constructor before its own constructor, but does it do the same with the destructor?)
(these random things, I always forget)
Maps
Searching Maps: Case Sensitivity
Summary: searching maps using the map.find("key")
function is case-sensitive.
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<string,int> some_map;
cout << "Creating a map with keys \"key1\" and \"key2\"." << endl;
some_map["key1"]=10;
some_map["key2"]=20;
map<string,int>::iterator i;
i = some_map.find("Key1");
if( i == some_map.end() ) {
cout << "The map could not find Key1." << endl;
} else {
cout << "The map did find Key1." << endl;
}
i = some_map.find("key1");
if( i == some_map.end() ) {
cout << "The map could not find key1." << endl;
} else {
cout << "The map did find key1." << endl;
}
return 0;
}
This returns:
Creating a map with keys "key1" and "key2". The map could not find Key1. The map did find key1.
Vectors
Pushing Back in an Empty Vector
Summary: yes, you can use push_back
on an empty vector. (Duh, this makes perfect sense now that I think about it. Not sure why I had to write this in the first place.)
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<double> abc;
abc.push_back(0.01);
abc.push_back(0.02);
abc.push_back(0.03);
abc.push_back(0.04);
for( vector<double>::iterator j = abc.begin(); j != abc.end(); ++j ) {
cout << "vector = " << *j << endl;
}
return 0;
}
will return:
vector = 0.01 vector = 0.02 vector = 0.03 vector = 0.04
Design Patterns
Singleton
Factory.h
class Factory {
public:
static Factory& self();
void print_it();
private:
Factory();
~Factory();
bool _private_member;
};
Factory.cc
#include "Factory.h"
#include <iostream>
Factory::Factory()
{
std::cout << "In the constructor." << std::endl;
_private_member = true;
}
Factory::~Factory()
{
std::cout << "In the destructor." << std::endl;
_private_member = false;
}
Factory& Factory::self()
{
static Factory s;
return s;
}
void
Factory::print_it()
{
std::cout << "Printing something: " << _private_member << std::endl;
}
driver.cc
#include <Factory.h>
#include <iostream>
int main()
{
Factory& f = Factory::self();
}
To compile:
g++ -c Factory.cc -I. g++ driver.cc Factory.o -o driver.x -I.
Style Guide
A comprehensive C++ style guide is available here: