|
Related YoLinux tutorials:
°Linux and C++
°C++ enumerations
°C++ Templates
°C++ STL
°C++ STL Map
°C++ String Class
°C++ Singleton
°C++ Coding Style
°C++ XML Beans
°C/C++ Dynamic Memory
°C++ Memory Corruption
°C/C++ Signal Handling
°C++ CGI
°Software development tools
°Advanced VI
°Emacs and C/C++
°YoLinux Tutorials Index
Free Information Technology Magazines and Document Downloads
Free Information Technology Software and Development Magazine Subscriptions and Document Downloads
|
C++ introduces some differences and extensions from the classic C struct as well as commonality and differences with the C++ class.
Simple example of a program using C++, a structure and a constructor:
-
// File: struct-test.cpp
//
// This example shows the use of a structure in C++ and how it behaves much
// like a class including the use of a contructor yet maintains the useability
// of a regular C structure.
#include <iostream>
#include <string>
using namespace std;
main()
{
struct DataElement {
string SVal;
int iVal;
bool hasData;
DataElement() // Example of a constructor used in a structure.
{
iVal=-1;
hasData=0;
}
} *RealData;
RealData = new DataElement [ 5 ];
// Assignment
RealData[0].SVal = "Value loaded into first structure element.";
RealData[0].hasData = 1; // True
cout << "First element 0: " << RealData[0].SVal << endl;
cout << " " << RealData[0].hasData << endl;
cout << "Second element 1: " << RealData[1].SVal << endl;
cout << " " << RealData[1].hasData << endl; // Show effect of contructor
cout << " " << RealData[1].iVal << endl; // Show effect of contructor
delete [] RealData; // Or: delete [5] RealData;
}
|
Compile: g++ struct-test.cpp
[Potential Pitfall]: In Red Hat Linux versions 7.x
one could omit the "using namespace std;" statement. Use of this
statement is good programming practice and is required in Red Hat 8.0.
[Potential Pitfall]: Red Hat 8.0 requires
the reference to "#include <fstream>". Red Hat versions 7.x
used "#include <fstream.h>".
Output: ./a.out
-
First element 0: Value loaded into first structure element.
1
Second element 1:
0
-1
The same example using typedef and a C++ initializer:
-
#include <iostream>
#include <string>
using namespace std;
typedef struct dataElement {
string SVal;
int iVal;
bool hasData;
dataElement() // Example of a constructor used in a structure.
: iVal(-1), hasData(0)
{}
} DataElement;
main()
{
DataElement *RealData;
RealData = new DataElement [ 5 ];
RealData[0].SVal = "Value loaded into first structure element.";
RealData[0].hasData = 1; // True
cout << "First element 0: " << RealData[0].SVal << endl;
cout << " " << RealData[0].hasData << endl;
cout << "Second element 1: " << RealData[1].SVal << endl;
cout << " " << RealData[1].hasData << endl; // Show effect of contructor
cout << " " << RealData[1].iVal << endl; // Show effect of contructor
delete [] RealData; // Or: delete [5] RealData;
}
|
Identical results as above example.
By contrast the typical "C" structure initialization is as follows:
-
#include <stdio.h>
typedef struct dataElement {
char *cVal;
int iVal;
} DataElement;
main()
{
DataElement RealData = {"Text goes here", 5 }; // "C" style initialization.
printf("%s \nInteger value=%d\n",RealData.cVal,RealData.iVal);
}
|
Compile: gcc struct-simple.c -o gcc struct-simple
Run: ./struct-simple
-
Text goes here
Integer value=5
C++ structure notes:
- The struct can employ a constructor to initalize variables.
- The struct can employ a destructor.
- The structure constructor can not be declared virtual.
- Structure member variables are public by default.
| C++ struct vs C++ struct vs C++ class: |
When using the GNU C++ compiler, the C++ struct and class behave the same.
While the C struct using an ANSI C compiler supports only variables, the GNU C++ (g++) compiler will support struct member functions, even virtual functions as well as public and private access controls and inheritance.
-
Features
| ANSI C struct | C++ struct | C++ class |
| member variables | yes | yes | yes |
| member functions | no | yes | yes |
| constructor support | no | yes | yes |
| destructor support | no | yes | yes |
| access control | no | yes | yes |
| default access | public | public | private |
| inheritance | no | yes | yes |
The only difference between a C++ struct and a C++ class is that a struct defaults members to public while a class defaults to private.
-
struct ABC {
int x;
};
main()
{
ABC abc;
abc.x = 5;
}
|
class ABC {
int x;
};
main()
{
ABC abc;
abc.x = 5;
}
|
$ g++ test.cpp
$
|
$ g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:2:7: error: ‘int ABC::x’ is private
test.cpp:7:8: error: within this context
|
| C++ struct and Virtual Functions: |
In memory, the C++ struct will behave just like the C struct until a virtual function is used, at which point the compiler will prefix the struct's memory with a pointer to the virtual table.
This is important especially when reading and writing structs across the network or to binary files as this prefixed pointer may have unintended consequences.
Also a pointer to the struct with a virtual function will not be a pointer to the first variable in the struct as the first element in the struct will be the pointer to the virtual table.
Also note that this pointer will reflect the word size of the hardware.
To mimic the ANSI C behavior of a struct, a C++ struct with a virtual function will require a serialization process to be programmed into the computional logic and flow or avoid the use of virtual functions.
Compilers other than GNU C++ are free to implement the memory layout differently, so proper serialization of data will be required before exchanging a C++ struct or object with other systems.
It is also permissible that other systems may rearrange the order of variables based on private/protected/public access definitions.
Memory order:
- A pointer to the virtual functions table is added only when the class has virtual methods.
Pointer size will be dependent on hardware and software word size. A 32 bit system will prefix a 32 bit pointer to the vtable while a 64 bit system will prefix a 64 bit pointer to the vtable.
- Base class variable data
- Class member variable data
The following example shows the memory layout of an object with class inheritance:
-
#include <iostream>
using namespace std;
struct AAA {
public:
int aaa;
AAA():aaa(0xff){};
AAA(int _aaa){aaa = _aaa;}
void printThis(){ cout << " Object this pointer memory: " << hex << (size_t)this << endl;}
};
struct BBB : AAA {
int bbb;
BBB():bbb(0x0000){};
BBB(int _aaa, int _bbb){aaa=_aaa;bbb=_bbb;};
};
main()
{
AAA aaa(0xffff);;
BBB bbb;
// AAA Print pointers - memory address of object and first member of object
cout << "AAA: " << sizeof(AAA) << " bytes." << endl;
cout << " Object memory address location &aaa: " << hex << (size_t)&aaa << endl;
cout << " First member variable Memory aaa.aaa: " << hex << (size_t)&aaa.aaa << endl;
aaa.printThis(); // Print object this pointer
cout << "BBB: " << sizeof(BBB) << " bytes." << endl;
cout << " Object memory address location &bbb: " << hex << (size_t)&bbb << endl;
cout << " First inherited member memory bbb.aaa: " << hex << (size_t)&bbb.aaa << endl;
cout << " First member variable Memory bbb.bbb: " << hex << (size_t)&bbb.bbb << endl;
bbb.printThis();
}
|
Run results:
-
AAA: 4 bytes.
Object memory address location &aaa: 7fffe3a8c410
First member variable Memory aaa.aaa: 7fffe3a8c410
Object this pointer memory: 7fffe3a8c410
BBB: 8 bytes.
Object memory address location &bbb: 7fffe3a8c400
First inherited member memory bbb.aaa: 7fffe3a8c400
First member variable Memory bbb.bbb: 7fffe3a8c404 -- BBB begins after AAA which 4 bytes in size
Object this pointer memory: 7fffe3a8c400
The beginning of BBB memory is occupied by AAA from which it inherits data variables.
The following example shows the memory layout effect of adding a virtual function and the accompanying vtable pointer prepended to the object's memory footprint:
-
#include <iostream>
using namespace std;
struct AAA {
public:
int aaa;
AAA():aaa(0xff){};
AAA(int _aaa){aaa = _aaa;}
void printThis(){ cout << " Object this pointer memory: " << hex << (size_t)this << endl;}
virtual void functionA(){};
};
struct BBB : AAA {
int bbb;
BBB():bbb(0x0000){};
BBB(int _aaa, int _bbb){aaa=_aaa;bbb=_bbb;};
void functionA(){};
};
main()
{
AAA aaa(0xffff);;
BBB bbb;
// AAA Print pointers - memory address of object and first member of object
cout << "AAA: " << sizeof(AAA) << " bytes." << endl;
cout << " Object memory address location &aaa: " << hex << (size_t)&aaa << endl;
cout << " First member variable Memory aaa.aaa: " << hex << (size_t)&aaa.aaa << endl;
aaa.printThis(); // Print object this pointer
cout << "BBB: " << sizeof(BBB) << " bytes." << endl;
cout << " Object memory address location &bbb: " << hex << (size_t)&bbb << endl;
cout << " First inherited member memory bbb.aaa: " << hex << (size_t)&bbb.aaa << endl;
cout << " First member variable Memory bbb.bbb: " << hex << (size_t)&bbb.bbb << endl;
bbb.printThis();
}
|
Run results:
-
AAA: 16 bytes.
Object memory address location &aaa: 7fff4b1d7fb0
First member variable Memory aaa.aaa: 7fff4b1d7fb8 -- 8 bytes offset for vtable pointer
Object this pointer memory: 7fff4b1d7fb0
BBB: 10 bytes.
Object memory address location &bbb: 7fff4b1d7fc0
First inherited member memory bbb.aaa: 7fff4b1d7fc8 -- 8 byte offset for vtable pointer
First member variable Memory bbb.bbb: 7fff4b1d7fcc -- 4 bytes additional offset for actual size of AAA
Object this pointer memory: 7fff4b1d7fc0
Note that sizeof() does not work properly when used on a struct with a virtual function (and thus with a vtable pointer).
Note that the starting memory address of the object is not the same as that for the first member variable. This is due to the vtable pointer which consumes 8 bytes for the pointer on a 64 bit system. The position of the begining variables has shifted by these 8 bytes.
The following example shows how a "C" union can be used with a constructor to initialize data.
-
#include <stdio.h>
typedef union uAA
{
double dVal;
int iVal[2];
uAA() : dVal(3.22) {}
} UAA;
main()
{
UAA rdata;
printf("Array output: %d %d \nDouble output: %lf \n",
rdata.iVal[0], rdata.iVal[1], rdata.dVal);
}
|
Compile: g++ union-test.cpp -o union-test
Run: ./union-test
-
Array output: 1546188227 1074381455
Double output: 3.220000
[Potential Pitfall]: The C++
difference - Structures used with union. A struct can NOT be used with
a constructor if it is to be used in a union. The C++ recognition of
the constructor in a struct converts it to a C++ class which is not
valid in a "C" union.
-
Typical use of a "C" union:
#include <stdio.h>
typedef struct
{
int iVal1;
int iVal2;
} DataElement;
typedef union
{
DataElement de;
int iVal[2];
} UAA;
main()
{
UAA rdata;
rdata.de.iVal1 = 0;
rdata.de.iVal2 = 1;
printf("Array output: %d %d \n",
rdata.iVal[0], rdata.iVal[1]);
}
|
Compile: gcc -o union-test union-test.c
Note: Compiles properly with the gcc and g++ compiler.
Run: ./union-test
Array output: 0 1
|
Use of C++ structure (with constructor) in a union:
#include <stdio.h>
typedef struct dataElement
{
int iVal1;
int iVal2;
dataElement() : iVal1(1), iVal2(2){};
} DataElement;
typedef union
{
DataElement de;
int iVal[2];
} UAA;
main()
{
UAA rdata;
printf("Array output: %d %d \n",
rdata.iVal[0], rdata.iVal[1]);
}
|
Compile: g++ -o union-test union-test.cpp
-
union-test.cpp:13: error: member `DataElement ::de' with constructor not allowed in union
|
C++ union notes:
- The union can employ a constructor to initalize variables.
- The union can employ a destructor.
- Union member functions can NOT be declared virtual.
- Union member variables are public by default.
- A union's data members can NOT be declared static.
- A union can not be used as a base class.
Why a tutorial on such a simple subject? While simple, it has
been overlooked by every C++ book I have ever seen. Many programmers I
have met didn't know that
constructors could be used with a C structure. I didn't know until I
was
told by another programmer. It was not covered by my professor nor was
it
in our very thourough C++ text book. This is just an FYI.
Books: |
-
 |
C++ How to Program
by Harvey M. Deitel, Paul J. Deitel
ISBN #0131857576, Prentice Hall
Fifth edition.
The first edition of this book (and Professor Sheely at UTA) taught me to
program C++. It is complete and covers all the nuances of the C++ language.
It also has good code examples. Good for both learning and reference.
|
|
|
|