Hi, I started learning C++ a couple of days ago as I hear it is a superior language to C for general purpose programming, and have a few questions.
Question 1:
This question regards using forward declared constant values as sizes for fixed length arrays.
I would like to be able to compile code like this:
Header:
1 2 3 4 5 6
|
class Example
{
private:
static unsigned const ARRAY_SIZE;
unsigned myArray[ARRAY_SIZE];
};
|
Source:
1 2 3 4
|
#include "Header.hpp"
unsigned const
ARRAY_SIZE = 10;
|
However, this does not compile as the size of class Example must be resolvable from the source in the header file. So I have considered a "solution" along the lines of having a file of constants as follows:
Constants:
1 2 3 4
|
namespace Constants
{
unsigned const ARRAY_SIZE = 10;
}
|
and then adding it in my makefile as a dependency which, when altered, causes total recompilation. The only advantage of this over the typical "make clean" followed by "make" to address the change of definitions which exist through necessity in a header file is that the rebuild is then automated by the make. However, it is obviously an inefficient compilation process. Is there a way to resolve this problem which I have missed?
Question 2:
This question regards polymorphism and memory allocation.
I have code like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
class Base
{
protected:
unsigned data;
public:
virtual void editData() = 0;
};
class A: public Base
{
public:
void editData() { data = 1; };
};
class B: public Base
{
public:
void editData() { data = 2; };
};
|
Now, in order to actually utilise this polymorphism, I need code like this:
Base *a[2] = { new A(), new B() };
a[0]->editData();
a[1]->editData();
and then at some point I require:
delete [] a;
Since inherited classes A and B add no additional size to the base class Base I would like to use a fixed length array of instances of A or B. This would avoid unnecessary memory allocation and additional pointer resolution. Have I overlooked some code structures to allow for inherited classes which do not increase the size of the base class?
Question 3:
This question regards forward declarations of enumerations.
I often define a lot of constants in my code for the obvious purpose of increasing readability. However, I cannot seem to get forward declarations of enumerations to work.
I am aware of the issue of data size resolution with forward declaration of enumerations, and am lead to believe that c++0x allows this to be resolved by giving the underlying type of the enumeration. However, I cannot find example code or get anything to compile. What I am currently trying is something like:
Header:
1 2 3 4 5
|
class Example
{
private:
enum E: unsigned;
};
|
Source:
1 2 3 4 5
|
enum Example::E
{
Val1 = 10,
Val2 = 20
};
|
Besides inability to compile forward declared enumerations, I don't know what the advantage of enumerations over constants is. For example, why would enumerations be better than say:
Header:
1 2 3 4 5 6 7
|
class Example
{
private:
static unsigned const
Val1,
Val2
};
|
Source:
1 2 3
|
unsigned const
Example::Val1 = 10,
Example::Val2 = 20;
|
Which works just fine and only has the somewhat superficial difference that enumerations define a type name associated with the enumeration, but if that is important it could be addressed with:
Header:
1 2 3 4 5 6 7 8
|
class Example
{
private:
typedef unsigned E;
static E const
Val1,
Val2
};
|
Source:
1 2 3
|
Example::E const
Example::Val1 = 10,
Example::Val2 = 20;
|
And I am lead to believe that typedefs follow the same scoping rules as enumerations.
Question 4:
To read/write an instance of a class, is the following acceptable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
#include <iostream>
#include <fstream>
class Example
{
private:
char data[DATA_LEN];
public:
char moreData[MORE_DATA_LEN];
void read(std::istream*);
void write(std::ostream*);
};
Example::read(std::istream *is)
{
is->read((char*)this, sizeof(Example));
}
Example::write(std::ostream *os)
{
os->write((char*)this, sizeof(Example));
}
|
Assuming the class:
- Contains no non-static pointers.
- Contains no virtual/override functions.
i.e. my question is can one assume that the data members of a class are stored contiuously and in the order in which they are declared? In particular, will multiple compilers consistently give the same file format as a result of this code?
The motivation behind this question is that it is clearly inefficient to read each field from an input stream with individual and unnecessary function calls to the input or output stream.
Question 5:
How are virtual functions implemented? My assumption was that a virtual function would be compiled as both the function and a data member in the class which is a pointer to the function, then overriding the function in an inherited class would create a new function and would override the pointer to the new function. Hence I made this test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
#include <iostream>
using namespace std;
class A
{
public:
virtual void Hello() { cout << "A" << endl; };
};
class B: public A
{
public:
void Hello() { cout << "B" << endl; };
};
int main(int argc, char *argv[])
{
A a = B();
a.Hello();
return 0;
}
|
This code, sadly, prints "A". Thus, I don't know how the compiler implements virtual functions. Interestingly, by adding a virtual function the sizeof A goes from 1 (what I believe is a dummy byte to disambiguate multiple instances of a class which has no data members by forcing instances to occupy different areas in memory), up to 4, the size of a pointer. However, when I try to interpret this memory and interpret it as a pointer to a function all I get is a crash - e.g.:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
#include <iostream>
using namespace std;
class A
{
public:
virtual void Hello() { cout << "A" << endl; };
};
int main(int argc, char *argv[])
{
A a = A();
unsigned *p = (unsigned*)&a;
void (*f)(A*) = (void (*)(A*)) (*p);
f(&a);
return 0;
}
|
As C++ forbids taking the address of a member function, I am left in the dark as to the implementation of virtual functions.
Thanks in advance for your help!
NB/ NO CODE IN THIS POST HAS BEEN TESTED, THERE MAY BE TRIVIAL SYNTAX ERRORS.