Like the how to use void I am wandering how to use class I know struct but class is a mystery
Thatâs a really big question depending on how deep you want to go.
Superficially the only difference between class
and struct
in C++ is that class
defaults to private
access while struct
defaults to public
access as per C++'s access specifiers.
But if you mean how to use them to full effect as in the whole object-oriented, member function using, inheritance using stuff, then thatâs going to take more than just a one page comment to explain.
Basically youâd have to read many tutorials, try a lot of experiments to get a grip on how it all works, and then practise and eventually move on to bigger, more complicated things.
I suggest focusing on member functions and access specifiers first since theyâre easy enough to get a grip on.
Inheritance on the other hand is a big thing because itâs part of the object orientation paradigm, which is a way of thinking about code.
At that point youâd have to actually learn about the object oriented paradigm itself, which involves a significant shift in thinking.
Learning a new paradigm is probably the closest thing the programming world has to a spiritual journey.
can you give me a example?
An example of what?
An example of an online tutorial?
An example of member functions?
An example of access specifiers?
An example of inheritance?
an example of using class or can u not do that simply. is it like a big thing?
I could give an example of some of the features of classes, but even if I show you examples of all the features, without reading about them it wonât do you much good. Itâs not something you can understand just by seeing, thereâs theory behind it that has to be understood before everything makes sense.
Iâve written some basic examples, but really youâd be better off reading some proper tutorials:
At the simplest level, to demonstrate the difference between struct
and class
using only member variables and access specifiers, these two things are equivalent:
struct Point
{
int X;
int Y;
};
class Point
{
public:
int X;
int Y;
};
And so are these:
struct Point
{
private:
int X;
int Y;
};
class Point
{
int X;
int Y;
};
As a demonstration of access specifiers, thereâs this:
class AcessDemo
{
public:
int PublicValue;
private:
int PrivateValue;
};
void SomeFunction(void)
{
AccessDemo demo;
demo.PublicValue = 5; // Ok
demo.PrivateValue = 10; // Compile error
}
The main reason you might want to make PrivateValue
private is because of a concept called information hiding.
In basic terms you want to keep certain variables private either to prevent them being modified by code that shouldnât be modifying them or to hide how a bit of code is implemented in case the implementation has to be changed (e.g. the code breaks, or the code is changed to be more efficient).
This is something that is easier to appreciate when youâve encountered the kind of problems it sets out to prevent.
A simple demonstration of member functions:
class Health
{
private:
float value;
public:
float getValue(void)
{
return this->health;
}
void heal(float amount)
{
this->health += amount;
}
void damage(float amount)
{
this->health -= amount;
}
};
void someFunction(void)
{
Health healthA;
healthA.heal(1000); // health.value is now 1000
healthA.damage(100); // health.value is now 900
Health healthB;
healthB.heal(500); // health.value is now 500
healthB.damage(10.5); // health.value is now 489.5
}
Member functions follow the principles of encapsulation in which an objectâs state is modified by operations being performed on it. These operations are bundled with the class rather than being separate entities.
A simple demonstration of constructors and destructors:
class Memory
{
private:
char * data;
size_t size;
public:
Memory(size_t size)
{
this->size = size;
this->data = (char*)malloc(size);
}
~Memory(void)
{
this->size = 0;
free(this->data);
}
size_t getSize(void) { return this->size; }
char getChar(size_t index)
{
// Boundry checking to prevent buffer overflow
if(index < 0 || index >= size) return '\0';
return data[index];
}
bool setChar(size_t index, char value)
{
// Boundry checking to prevent buffer overflow
if(index < 0 || index >= size) return false;
data[index] = value;
return true;
}
};
void someFunction(void)
{
Memory memory = Memory(256); // Constructor is called, allocate 256 bytes
auto size = memory.getSize(); // Gets size, which is 256
memory.setChar(0, `a`); // Puts an 'a' at position 0
auto c = memory.getChar(0); // Gets the 'a' at position 0
} // End of function, memory falls out of scope, destructor is called
Constructors and destructors are a very useful feature, many languages have constructors, but few have destructors.
Constructors ensure that an object is properly initialised to a valid value whilst destructors make sure proper cleanup operations are performed: freeing memory, closing files, closing sockets.
These underly C++'s RAII principle (Resource Acquisition Is Initilisation).
Inheritance is something thatâs quite difficult to demonstrate.
Many demonstrations resort to contrived âmammal inherits animalâ or âcircle inherits shapeâ examples.
Instead Iâm going to try to give a more âreal worldâ example, but itâs not a particularly kind example. For this demo, assume the Memory
class from the earlier example is also available.
class TextWriter
{
virtual ~TextWriter(void) {}
virtual size_t write(const char * text) = 0;
};
class MemoryWriter : public TextWriter
{
private:
Memory * memory;
size_t index;
public:
MemoryWriter(Memory * memory)
{
this->memory = memory;
this->index = 0;
}
size_t write(const char * text) override
{
size_t charsWritten = 0;
while((*text != '\0') && (this->index < this->memory->getSize()))
{
this->memory->setChar(this->index, *text);
++text;
++this->index;
++charsWritten;
}
return charsWritten;
}
};
class FileWriter : public TextWriter
{
private:
FILE * file;
public:
FileWriter(const char * filename, const char * mode)
{
this->file = fopen(filename, mode);
}
~FileWriter(void)
{
fclose(this->file);
}
size_t write(const char * text) override
{
return fwrite(text, 1, strlen(text), this->file);
}
};
void writeSomething(TextWriter * writer)
{
writer->write("Something");
}
void someFunction(void)
{
Memory memory = Memory(500);
MemoryWriter mWriter = MemoryWriter(&memory);
FileWriter fWriter = FileWriter("file.txt", "w");
writeSomething(&mWriter);
writeSomething(&fWriter);
}
Here the TextWriter
class is an abstract class (i.e. it has no implementation, itâs just an interface). It has a virtual destructor, which you need not worry about, and a virtual function called write
that attempts to write a string and returns the number of characters that were written.
The MemoryWriter
uses our earlier Memory
class as its backing store and writes the string to Memory
.
The FileWriter
class opens a file and writes the string to the file it has opened, making sure to close the file when itâs destroyed.
This code is actually simplified for demonstration purposes, to make it properly functional and well designed would require explaining other things that are even further advanced.
For now, this is the crux of inheritance:
The TextWriter
class is whatâs called the âparentâ class or (in Java parlance) the âsuperclassâ.
It represents some kind of interface that performs a certain job.
In this case its job is to write text.
What it writes the text to is unspecified because itâs unimportant.
The point is that itâs an agreed upon interface for writing text.
The FileWriter
and MemoryWriter
are âchildâ classes or (in Java parlance) the âsubclassesâ.
They are responsible for filling in the blanks - they provide the implementation for the TextWriter
's interface.
They are what decides where the text gets written to.
One writes to a file on a hard drive or usb stick or something, the other writes to a block of memory in RAM.
But the important thing is that they both adhere to the rules of TextWriter
: they accept a string, they âwriteâ that string (whatever that means to them), and they return how many characters they have written.
This one of the main things define inheritance.
Thereâs much more too it than that, thereâs also how member variables and member functions get inherited, thereâs how the child classes can be treated as if they were their parent.
Itâs a deep topic and one pretty much nobody on the planet could summarise in less than several pages.
So all in all, thereâs your drop in the ocean.
The truth of the matter is thereâs no simple answer to âwhat is a classâ or âhow do I use a classâ.
Itâs so closely tied to object orientation that beyond just using the simple parts like member functions, itâs something that requires lots of tutorials and lots of reading.
Itâs a big thing to understand and it takes work getting there, but itâs totally worth it.
It turns your view of programming upside down and it will almost certainly make you a better programmer in the process.
Thereâs no rush to learn it all at once though, the journey of a thousand miles begins with but a single step.
Just make sure to read and practice every day and eventually youâll hit a point of understanding where you can start looking at your old code and finding ways to make it better, ways to give it a more object-oriented approach.