Making Enum work - c++

In player.h I have enum race {Living, Dead, Nature,None};
In player.cpp I have
race myRace;
void Player::addPlayer(int x)
{
cout<<"added player"<<x<<endl;
this->karma=0;
this->myTurn=false;
myRace=race(4);
}
So this should , when a player is created make myRace = None.
Now in Main.cpp I want to check a players race, how would i do this?
I tried if (player[x].myRace=None) but of course that wont work..

This should work: myRace = None; and it's the recommended way to use an enum to avoid another mistake that you made, 4 is not a valid integer option for your enum, because Living is 0 and None will be 3.

Enums should work the way you describe. Unfortunately you only provided modified, unrunnable code and no compiler errors or other output. However, the following code should show you how to use enums: (Live demo)
#include <iostream>
enum Race { None, Living, Dead, Nature}; // always put invalid as the 0 entry.
class Player
{
uint32_t m_karma;
bool m_myTurn;
Race m_myRace;
public:
void addPlayer(int x_)
{
std::cout << "added player " << x_ << std::endl;
m_karma = 0;
m_myTurn = false;
m_myRace = None;
}
};
int main(int argc, const char** argv)
{
Player fred;
fred.addPlayer(1);
return 0;
}
If you have a C++11 capable compiler you can be more specific and use "enum Class" which will force you to qualify enumerations (i.e. Race::None). (Live demo)
#include <iostream>
enum class Race { None, Living, Dead, Nature}; // always but invalid as the 0 entry.
class Player
{
uint32_t m_karma;
bool m_myTurn;
Race m_myRace;
public:
void addPlayer(int x_)
{
std::cout << "added player " << x_ << std::endl;
m_karma = 0;
m_myTurn = false;
m_myRace = Race::None;
}
};
int main(int argc, const char** argv)
{
Player fred;
fred.addPlayer(1);
return 0;
}
"player[x].race = None" won't work because that is assignment, not a test for equality. You don't say why it didn't work, I'm going to assume - if it wasn't just the wrong variable name - because it was private or inaccessible. In that case, just add a member function to return the race:
class Player {
...
public:
Race getRace() const { return m_myRace; }
...
};

The whole point of enums is to do away with magical numbers, so although enums are convertible to integers, getting enums from integers is counter productive.
You should write myRace=None, rather than myRace=4.
Secondly unless, you explicitly specify otherwise in your declaration of your enum type, enums starts at 0, so None corresponds to 3 rather than 4.
Thirdly, in C++ you don't have to write this->member_name to access a member variable. If you want to differentiate members from nonmembers, you can save many keystrokes by adopting a much shorter naming convention. (Such as appending _ to member variable names).
Finaly, = in C++ means assignment, NOT equality comparison.
if (player[x].myRace=None) effectively means player[x].myRace=None; if (player[x].myRace), i.e. the condition is always true, since player[x].myRace==None==3. Most of the time, the assignment operator inside if conditions is an error and your compiler might warn you about this.
Also, it's kind of weird for a member variable to access your myRace global (and globals are usually a bad idea). If myRace is not a global, then a function can access it only if a pointer or a reference is passed to it as an argument or if myRace is made as a member variable and your function is a method of the same class.

Be careful here ! myRace is not part of Player class. So you will have one instance of myRace, whatever the number of players.
You should make myRace part of your class. If you don't, everytime you create a new player, the race changes !
If this is what you want, it should be a static member of your player class, so you could add a static getter tro retrieve it
class Player{
static int myRace;
public:
static int GetMyRace(){
return myRace;
}
...
}
and then, access it like this :
Player::GetMyRace();

Related

Declare class member variables inside class member functions

Is there any technique or compiler extension keyword to declare class member variables inside class member functions? Something like
struct test_t{
void operator ()(){
instance_local int i = 0;
}
};
The best that came in my mind was using thread_local and then executing the member function inside another thread, but this would be too ugly to be useful.
EDIT: example
Well I'm really sorry for the following probably confusing example (it is related to my question yesterday Is there any problem in jumping into if(false) block?). I really tried to make a less confusing up...
#include <iostream>
#define instance_local thread_local
struct A{
A(int i) :
i(i)
{
}
void dosomethinguseful(){
std::cout << i << std::endl;
}
int i;
};
struct task1{
int part;
task1() : part(0){}
void operator ()(){
int result_of_calculation;
switch (part) {
case 0:{
//DO SOME CALCULATION
result_of_calculation = 5;
instance_local A a(result_of_calculation);
if(false)
case 1:{ a.dosomethinguseful();}
part++;
}
default:
break;
}
}
};
int main(){
task1 t;
t();
t();
return 0;
}
instance_local A a(result_of_calculation); that is what i could get from such a keyword instead of making a smart pointer for a.
You're describing a coroutine. Here a rough draft of what it could look like (I'm not an expert in coroutine)
auto task1() -> some_awaitable_type {
result_of_calculation = 5;
A a(result_of_calculation);
co_yield;
a.dosomethinguseful();
}
This could be called like this:
some_awaitable_type maybe_do_something = task1();
// calculation done here
// dosomethinguseful called here
co_await maybe_do_something();
There is not. The compiler needs to know the structure of the class without compiling all the method implementations. If you could slip instance_local int foo into a method body, that would make the size of the data structure 4 bytes larger.
On a more principled level, it's not good to hide data. The equivalent feature for global variables that you might be thinking of, static local variables, is a carryover from C that is widely considered to be an anti-pattern:
Why are static variables considered evil?
Not directly, no.
You could define a:
static std::map<test_t*, int> is;
…where the first part of each element is a this pointer.
But, why?
Make a member variable.

Union and Class

I have a lot of free time ( there are also the Xmas holidays incoming! ) so, I tried to merge my two passions, video games and c++.
It is not a real video game project, was just some console script using classes.
So, here it comes the problem;
#include <stdafx.h>
#include <iostream>
class m4a1 {
public:
int Damage = 12;
int Mag = 30;
};
class ak47 {
public:
int Damage = 14;
int Mag = 24;
};
union Gun_Union {
m4a1 M4A1_Union;
ak47 Ak47_Union;
};
class Player {
public:
Gun_Union Gun_Player;
int Health = 200;
};
template <typename Type>
void Shot(Type* Player_Obj) {
Player_Obj->Gun_Player->AK47_Union->Mag--;
Player_Obj->Health = Player_Obj->Health - Player_Obj->Gun_Player->AK47_Union->Damage;
}
int main() {
Player Player_Obj;
Player_Obj.Gun_Player;
Shot <Player> (&Player_Obj);
std::cout << Player_Obj.Health;
}
At the line 35 it gives me the error
Player::Player(void) trying to refer to an eliminate function.
I discovered that changing Gun_Union with any other type in the class Player (line 25) it doesn't give me an error.
I also ask if the command Player_Obj.Gun_Player = Ak47_Union is possible;
Sorry for bad English.
To answer your original question, your union has non-trivial members (because of the initializers), but has no constructor. You need to tell the compiler which of the union's members you want to have initially, because the compiler must construct one or the other. That can be done for example by giving the union a constructor.
And then you're mixing . and -> operators.
Here's a version that compiles (I don't dare call it "fixed" though):
#include <iostream>
class m4a1 {
public:
int Damage = 12;
int Mag = 30;
};
class ak47 {
public:
int Damage = 14;
int Mag = 24;
};
union Gun_Union {
m4a1 M4A1_Union;
ak47 Ak47_Union;
Gun_Union() : Ak47_Union() {} // <=== the initial state is ak47
};
class Player {
public:
union Gun_Union Gun_Player;
int Health = 200;
};
template <typename Type>
void Shot(Type* Player_Obj) {
Player_Obj->Gun_Player.Ak47_Union.Mag--;
Player_Obj->Health = Player_Obj->Health - Player_Obj->Gun_Player.Ak47_Union.Damage;
}
int main() {
Player Player_Obj;
Player_Obj.Gun_Player;
Shot <Player>(&Player_Obj);
std::cout << Player_Obj.Health;
}
I also ask if the command Player_Obj.Gun_Player = Ak47_Union is possible; Sorry for bad English.
So what you're trying to do here is set the player's current weapon to an ak47. Here's the problem. Your union represents a class, not just a regular type. This is a problem for a few reasons.
A class is useful because it provides a blueprint from which to create similar but ultimately different objects. Since all of your weapon classes have the same structure (damage and magsize), there's no reason to have separate classes for each weapon.
Furthermore, a class here is tricky because in order for you to use a class, you must first either instantiate it or declare it's member functions static. The problem here comes from the fact that you're using a union to handle the player weapon. A union won't work because unions by definition hold things (one at a time), which is not a thing here because we want a static class.
Now, you could instantiate your weapon classes and actually add them to the union, like so:
int main()
{
Player Player_Obj;
Player_Obj.Gun_Player;
// Remember to pick better names for classes, not the metasynctactic
// b.s. I'm using
m4a1 m4a1_class_instance;
ak47 ak47_class_instance;
// Populate the union
union Gun_Union weapons;
weapons.Ak47_Union = ak47_class_instance;
// Finally, set player weapon
Player_Obj.Gun_player = weapons;
// <Rest of program...>
As I'm sure you can tell, this is clunky and doesn't really make sense. Why are we istantiating those classes? It doesn't really make sense. I think a redesign here would be great, especially because you wouldn't have to deal with the union, which was tripping you up with regards to setting the player's weapon. Here is a pretty basic one.
// Using constants for simplicity
// Weapon Ids
const auto M4A1 = 1000;
const auto AK47 = 1001;
const auto FIRST_WEAPON_ID = M4A1;
const auto LAST_WEAPON_ID = AK47;
class Player {
int weapon_id;
int health;
int damage;
int magazine_capacity;
int magazine;
public:
void setWeapon(const int weapon_id) {
// Validate id first; you should somehow handle error,
// I'm just exiting the function here
if ((weapon_id < FIRST_WEAPON_ID) || (weapon_id > LAST_WEAPON_ID)) return;
switch (weapon_id) {
case M4A1: {
damage = 12;
magazine_capacity = 30;
} break;
case AK47: {
damage = 14;
magazine_capacity = 24;
} break;
default: // Error should have been handled in validation, but
// it's best practice to guard your code everywhere
return;
}
}
};
This wouldn't be the full class obviously, I only wrote one function just to show you how I would implement a more naive method, but the actually implementation details are up to you, I would really stress the design concepts, specifically the following:
Accessing Class Members
You don't want to access class members directly, especially when you're talking about a pointer. The problem of 'who owns the data pointed to by the pointer' is a significant one, and it's why we now have shared and unique pointers. Regardless of which pointer you use though, you should have something like <return-type> getValue() const. That way your data is protected by a layer of indirection. Likewise, to set a value you can do something like void setValue(const <type> value) and now you can do validation or whatever in that function.
Unions
First, I don't recommend using unions. In your particular case, using a union doesn't really make sense because you already have the pointer in the player class (before you edited your question), which means a player can already only hold one. Having a union doesn't add anything at that point. Additionally, using unions isn't recommended, mostly because you lose some type-safety. If you do want something union-like, you might want to check out std::variant in the STL.
Your Template Function
Generally speaking, template functions are for generic programming, where they can take in a type T and you don't have to worry about rewriting code unnecessarily. In your case, it shouldn't apply.
You mentioned you were just doing this for practice, so I understand a clean design wasn't your goal, but I think it's never too early to start thinking about design principles.

C++ How to avoid access of members, of a object that was not yet initialized

What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
I wrote a small example which I think explains the problem very well.
#include <vector>
using namespace std;
class container{public:container(){}
vector<int> LongList;
bool otherInfo;
};
class Ship
{
public:Ship(){}
container* pContainer;
};
int main()
{
//Create contianer on ship1
Ship ship1;
ship1.pContainer = new container;
ship1.pContainer->LongList.push_back(33);
ship1.pContainer->otherInfo = true;
Ship ship2;
//Transfer container from ship1 onto ship2
ship2.pContainer = ship1.pContainer;
ship1.pContainer = 0;
//2000 lines of code further...
//embedded in 100 if statements....
bool info = ship1.pContainer->otherInfo;
//and the program crashes
return 0;
}
The compiler cannot determine if you are introducing undefined behavior like shown in your example. So there's no way to determine if the pointer variable was initialized or not, other than initializing it with a "special value".
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
The best practice is always to initialize the pointer, and check before dereferencing it:
class Ship {
public:
Ship() : pContainer(nullptr) {}
// ^^^^^^^^^^^^^^^^^^^^^
container* pContainer;
};
// ...
if(ship1.pContainer->LongList) {
ship1.pContainer->LongList.push_back(33);
}
As for your comment:
So there are no compiler flags that could warn me?
There are more simple and obvious cases, where the compiler may leave you with a warning:
int i;
std::cout << i << std::endl;
Spits out
main.cpp: In functin 'int main()':
main.cpp:5:18: warning: 'i' is used uninitialized in this function [-Wuninitialized]
std::cout << i << std::endl;
^
See Live Demo
One good practice to enforce the checks is to use std::optional or boost::optional.
class Ship
{
public:
Ship() : pContainer(nullptr) {}
std::optional<container*> Container()
{
if(!pContainer)
return {};
return pContainer;
}
private:
container* pContainer;
};
It will force you (or better: provide a firm reminder) to check the result of your getter:
std::optional<container*> container = ship1.Container();
container->otherInfo; // will not compile
if(container)
(*container)->otherInfo; // will compile
You would always need to check the result of operation if you use pointers. What I mean is that with optional the situation is more explicit and there's less probability that you as the programmer will forget to check the result.
It seems that you are looking for a way to make your code
bool info = ship1.pContainer->otherInfo;
work even though the pContainer may be null.
You can use a sentinel object, which holds some default data:
container default_container;
default_container.otherInfo = false; // or whatever the default is
Then use a pointer to the sentinel object instead of a null pointer:
//Transfer container from ship1 onto ship2
ship2.pContainer = ship1.pContainer;
ship1.pContainer = &default_container; // instead of 0
//2000 lines of code further...
//embedded in 100 if statements....
bool info = ship1.pContainer->otherInfo;
If you use this, you should make sure the sentinel object cannot be destroyed (e.g. make it a static member, or a singleton).
Also, in the constructor, initialize your pointers so they point to the sentinel object:
class Ship
{
public: Ship(): pContainer(&default_container) {}
...
};
I found an additional solution. It is admittedly not preventing the access of uninitialized objects, but at least the program crashes AND returns an error message, that enables us to correct our mistake. (This solution is particularly for the g++ compiler.)
First of all set the compiler flag _GLIBCXX_DEBUG. Then instead of naked pointer use unique_ptr.
#include <vector>
#include <iostream>
#include <memory>
using namespace std;
class container{
public:container(){}
int otherInfo = 33;
};
class Ship
{
public:Ship(){}
std::unique_ptr<container> upContainer;
};
int main()
{
Ship ship1;
cout<<ship1.upContainer->otherInfo<<endl;
return 0;
}
This code will produce an error:
std::unique_ptr<_Tp, _Dp>::pointer = container*]: Assertion 'get() != pointer()' failed.
Hence telling us that we should probably include an if(ship1.upContainer) check.
What are good practice options for passing around objects in a program, avoiding accessing non initialized member variables.
Good practice would be to initialize everything in the constructor.
Debatable better practice is to initialize everything in the constructor and provide no way of modifying any members.

c++ class setter sets variables different when argumentname and variable name are equal

I'm completly new to c++ and I found something I don't understand and which I cannot find the answer for(also I'm sure it has been asked a lot, so point me to a thread would also be nice).
Example code:
#include <iostream>
class Car {
int doors;
public:
void set_doors(int doors){
doors = doors;
}
int get_doors(){
return doors;
}
};
int main()
{
Car ford;
ford.set_doors(3);
std::cout << ford.get_doors() << std::endl;
}
So when I run the code it returns always an int of length 9.
I know that the issue is happening because in
void set_doors(int doors)
I'm using the same name for the argument and the variable I'd like to change.
If I would change the code to
void set_doors(int newdoors){
doors = newdoors;
}
everything will work perfectly.
My question is:
Why does the code behave like this, when using the name for the variable which I like to modify and the argument name?
Please explain it in an easy way ;)
Thanks
Best
Why does the code behave like this, when using the name for the variable which I like to modify and the argument name?
Because the rules of C++ require it to behave this way: names of local variables and parameters "win" over member variables. You should get a compiler warning on this assignment, saying that the assignment has no effect (it assigns the value of a parameter back to itself).
One of idiomatic ways of resolving this is as follows:
this->doors = doors;
This is the way the language lets you resolve situations when an unqualified name could refer to more than one thing.
Your code has undefined behaviour, because you attempt to read an uninitialized variable. In the following function:
void set_doors(int doors){
doors = doors;
}
doors always refers to the function argument, not to the member variable. In other words, you self-assign the function argument and your doors member variable is left untouched. What's worse is the member variable is never initialized. Reading it in get_doors produces 9 only by sheer coincidence on your machine. The program could just do anything.
You can fix your setter function like this:
void set_doors(int doors){
this->doors = doors;
}
Still, your class would be very easy to use incorrectly, because it is not obvious that one should have to call set_doors before get_doors actually works. You want to initialize doors to 0 in the constructor:
class Car {
int doors;
public:
Car() : doors(0) {}
void set_doors(int doors){
this->doors = doors;
}
int get_doors(){
return doors;
}
};
Once inside the function get_doors, the argument 'doors' hides the member variable 'doors'. So the assignment 'doors = doors' basically assigns the function parameter doors to doors and the member variable is still left undefined.
Also, I would ideally not design the class this way, I would rather setup the class member variables in the constructor.
*
Class Car {
int doors; public:
Car(int doors): doors(doors) {}
int get_door_count(){ return doors; } };
*
Notice that in this case the compiler can correctly differentiate between the function argument doors and the member variable doors when using the member initialiser syntax.

Trouble implementing min Heaps in C++

I'm trying to implement a minheap in C++. However the following code keeps eliciting errors such as :
heap.cpp:24:4: error: cannot convert 'complex int' to 'int' in assignment
l=2i;
^
heap.cpp:25:4: error: cannot convert 'complex int' to 'int' in assignment
r=2i+1;
^
heap.cpp: In member function 'int Heap::main()':
heap.cpp:47:16: error: no matching function for call to 'Heap::heapify(int [11], int&)'
heapify(a,i);
^
heap.cpp:47:16: note: candidate is:
heap.cpp:21:5: note: int Heap::heapify(int)
int heapify(int i) //i is the parent index, a[] is the heap array
^
heap.cpp:21:5: note: candidate expects 1 argument, 2 provided
make: * [heap] Error 1
#include <iostream>
using namespace std;
#define HEAPSIZE 10
class Heap
{
int a[HEAPSIZE+1];
Heap()
{
for (j=1;j<(HEAPISZE+1);j++)
{
cin>>a[j];
cout<<"\n";
}
}
int heapify(int i) //i is the parent index, a[] is the heap array
{
int l,r,smallest,temp;
l=2i;
r=2i+1;
if (l<11 && a[l]<a[i])
smallest=l;
else
smallest=i;
if (r<11 && a[r]<a[smallest])
smallest=r;
if (smallest != i)
{
temp = a[smallest];
a[smallest] = a[i];
a[i]=temp;
heapify(smallest);
}
}
int main()
{
int i;
for (i=1;i<=HEAPSIZE;i++)
{
heapify(a,i);
}
}
}
Ultimately, the problem with this code is that it was written by someone who skipped chapters 1, 2 and 3 of "C++ for Beginners". Lets start with some basics.
#include <iostream>
using namespace std;
#define HEAPSIZE 10
Here, we have included the C++ header for I/O (input output). A fine start. Then, we have issued a directive that says "Put everything that is in namespace std into the global namespace". This saves you some typing, but means that all of the thousands of things that were carefully compartmentalized into std:: can now conflict with names you want to use in your code. This is A Bad Thing(TM). Try to avoid doing it.
Then we went ahead and used a C-ism, a #define. There are times when you'll still need to do this in C++, but it's better to avoid it. We'll come back to this.
The next problem, at least in the code you posted, is a misunderstanding of the C++ class.
The 'C' language that C++ is based on has the concept of a struct for describing a collection of data items.
struct
{
int id;
char name[64];
double wage;
};
It's important to notice the syntax - the trailing ';'. This is because you can describe a struct and declare variables of it's type at the same time.
struct { int id; char name[64]; } earner, manager, ceo;
This declares a struct, which has no type name, and variables earner, manager and ceo of that type. The semicolon tells the compiler when we're done with this statement. Learning when you need a semicolon after a '}' takes a little while; usually you don't, but in struct/class definition you do.
C++ added lots of things to C, but one common misunderstanding is that struct and class are somehow radically different.
C++ originally extended the struct concept by allowing you to describe functions in the context of the struct and by allowing you to describe members/functions as private, protected or public, and allowing inheritance.
When you declare a struct, it defaults to public. A class is nothing more than a struct which starts out `private.
struct
{
int id;
char name[64];
double wage;
};
class
{
public:
int id;
char name[64];
double wage;
};
The resulting definitions are both identical.
Your code does not have an access specifier, so everything in your Heap class is private. The first and most problematic issue this causes is: Nobody can call ANY of your functions, because they are private, they can only be called from other class members. That includes the constructor.
class Foo { Foo () {} };
int main()
{
Foo f;
return 0;
}
The above code will fail to compile, because main is not a member of Foo and thus cannot call anything private.
This brings us to another problem. In your code, as posted, main is a member of Foo. The entry point of a C++ program is main, not Foo::main or std::main or Foo::bar::herp::main. Just, good old int main(int argc, const char* argv[]) or int main().
In C, with structs, because C doesn't have member functions, you would never be in a case where you were using struct-members directly without prefixing that with a pointer or member reference, e.g. foo.id or ptr->wage. In C++, in a member function, member variables can be referenced just like local function variables or parameters. This can lead to some confusion:
class Foo
{
int a, b;
public:
void Set(int a, int b)
{
a = a; // Erh,
b = b; // wat???
}
};
There are many ways to work around this, but one of the most common is to prefix member variables with m_.
Your code runs afoul of this, apparently the original in C passed the array to heapify, and the array was in a local variable a. When you made a into a member, leaving the variable name exactly the same allowed you not to miss the fact that you no-longer need to pass it to the object (and indeed, your heapify member function no-longer takes an array as a pointer, leading to one of your compile errors).
The next problem we encounter, not directly part of your problem yet, is your function Heap(). Firstly, it is private - you used class and haven't said public yet. But secondly, you have missed the significance of this function.
In C++ every struct/class has an implied function of the same name as the definition. For class Heap that would be Heap(). This is the 'default constructor'. This is the function that will be executed any time someone creates an instance of Heap without any parameters.
That means it's going to be invoked when the compiler creates a short-term temporary Heap, or when you create a vector of Heap()s and allocate a new temporary.
These functions have one purpose: To prepare the storage the object occupies for usage. You should try and avoid as much other work as possible until later. Using std::cin to populate members in a constructor is one of the most awful things you can do.
We now have a basis to begin to write the outer-shell of the code in a fashion that will work.
The last change is the replacement of "HEAPSIZE" with a class enum. This is part of encapsulation. You could leave HEAPSIZE as a #define but you should expose it within your class so that external code doesn't have to rely on it but can instead say things like Heap::Size or heapInstance.size() etc.
#include <iostream>
#include <cstdint> // for size_t etc
#include <array> // C++11 encapsulation for arrays.
struct Heap // Because we want to start 'public' not 'private'.
{
enum { Size = 10 };
private:
std::array<int, Size> m_array; // meaningful names ftw.
public:
Heap() // default constructor, do as little as possible.
: m_array() // says 'call m_array()s default ctor'
{}
// Function to load values from an istream into this heap.
void read(std::istream& in)
{
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
}
return in;
}
void write(std::ostream& out)
{
for (size_t i = 0; i < Size; ++i)
{
if (i > 0)
out << ','; // separator
out << m_array[i];
}
}
int heapify(size_t index)
{
// implement your code here.
}
}; // <-- important.
int main(int argc, const char* argv[])
{
Heap myHeap; // << constructed but not populated.
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
myHead.write(std::cout);
return 0;
}
Lastly, we run into a simple, fundamental problem with your code. C++ does not have implicit multiplication. 2i is the number 2 with a suffix. It is not the same as 2 * i.
int l = 2 * i;
There is also a peculiarity with your code that suggests you are mixing between 0-based and 1-based implementation. Pick one and stick with it.
--- EDIT ---
Technically, this:
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
is poor encapsulation. I wrote it this way to draw on the original code layout, but I want to point out that one reason for separating construction and initialization is that it allows initialization to be assured that everything is ready to go.
So, it would be more correct to move the heapify calls into the load function. After all, what better time to heapify than as we add new values, keeping the list in order the entire time.
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
heapify(i);
}
Now you've simplified your classes api, and users don't have to be aware of the internal machinery.
Heap myHeap;
myHeap.load(std::cin);
myHeap.write(std::cout);