Creating Class Objects from Static Functions - c++

Suppose I have a code as following.
class Color
{
static Color a;
public:
static Color newColor(int r,int g,int b){
Color color;
color.setR(r);
color.setG(g);
color.setB(b);
return color;
}
}
Is it alright to initialize the static variable 'a' using 'Color a = Color::newColor(255,0,0);'
I think I read somewhere that creating the instance using this method will create two instances of the class. What is the right way of doing this?

Yes Color gets instantiated twice
the local variable color in newCOlor and
the static Color a (since you are returning an object, a member-wise copy will happen at the static variable definition/initialization).
Be sure to put Color::a = Color::newColor(255,0,0); in a cpp/cc file, meaning not in a header file.

Try this for size:
struct Color
{
int R, G, B;
};
Color a = {255, 0, 0};

Related

C++ passing "default" struct to function

I'm trying to figure out how I can "pass default struct values" to a function without initializing the struct, this is what I have now:
struct Color3i
{
Color3i(): r(255), g(255), b(255) { }
int r, g, b;
};
void CCore::Color(Color3i color)
{
double red, green, blue;
red = color.r / 255.0f;
green = color.g / 255.0f;
blue = color.b / 255.0f;
glColor3f(red,green,blue);
}
Color3i defaultColor;
Core.Color(defaultColor);
What I'm trying to do would look like this but this clearly doesn't work:
Core.Color(Color3i defaultColor);
How would I pass the struct to the function without initializing it with Color3i defaultColor; is this possible?
Sorry if this has been asked before but I tried searching the interwebs but I couldn't find anything (maybe I'm using the wrong keywords to search)
You should just be able to do this:
Core.Color(Color3i());
That is, call the default constructor to initialize a new instance, and pass it.
There are a few ways to pass an information that you want the color to be default. The simplest one is given in the comments already:
Core.Color(Color3i())
If you want the code to be shorter, you can set the default value in the function parameter you invoke:
void CCore::Color(Color3i color = Color3i()) { ... }
....
Core.Color(); //no argument = default
If you want to be more descriptive instead, you can create a static function acting as a constructor in the Color:
struct Color3i {
Color3i(): r(255), g(255), b(255) { }
int r, g, b;
static Colo3i defaultColor() { return Color3i(); }
};
...
Core.Color(Color3i::defaultColor());
Finally, if you want to control the context where the default color can be used, you can create a new dummy enum type and overload the function(s) to accept the default version explicitly:
enum DefaultColorEnum {
DefaultColor
};
void CCore::Color(Color3i color) {
... //normal code
}
void CCore::Color(DefaultColorEnum) { //ignore the parameter value, the type is what matters
Color(Color3i()); //invoke the generic version with default value
}
...
Core.Color(DefaultColor);
It all depends on what you actually wants to achieve...

Is there any way to create instance and assign values to data members in namespace?

To make the code looks clean, I declare a class MaterialTexture in namespace Material to store the light attributes for OpenGL. And I want to create instance(such as metal, plastic) for this class in the same namespace.
I do some googling and find that a previous discussion shows that data members can't be assigned in the namespace. And the constructor is suggested to initialize the data members.
However, there're 12 data members in my case, and it would be tedious to pass 12 arguments to construct a instance. Instead, I want to use three functions (such as setDiffuse() ) to set the value of each instance.
namespace Material
{
class MaterialTexture
{
private:
float diffuse[4];
float specular[4];
float ambient[4];
public:
// Three functions below set the values for data members above.
void setDiffuse(float R, float G, float B, float A);
void setSpecular(float R, float G, float B, float A);
void setAmbient(float R, float G, float B, float A);
/* the following function tell the OpenGL how to draw the
Texture of this kind of Material and is not important
here. */
void setMaterial();
};
void MaterialTexture::setDiffuse(float R, float G, float B, float A)
{
diffuse[0]=R; diffuse[1]=G; diffuse[2]=B; diffuse[3]=A;
}
// Create instances plastic and metal
MaterialTexture plastic;
plastic.setDiffuse(0.6, 0.0, 0.0, 1.0);
...
MaterialTexture metal;
metal.setDiffuse(...);
...
}; // end of namespace
Thus, to create a red-plastic like sphere, I only need to type following codes in the display call back:
Material::MaterialTexture::plastic.setMaterial();
glutSolidSphere(...);
Compile the above code with g++, it gives the error:
error: ‘plastic’ does not name a type
and
error: ‘metal’ does not name a type
in the line of the three setting functions (such as setDiffuse() ) of each instance.
Thus it seems not only assignment directly in namespace, but functions contain assignment are not allowed... Am I right? Is there any other way to fix this? Or, are there some other way to facilitate the OpenGL programing?
Beyond the immediate problem with your code (all executable code has to be within a function, which is not the case in your example), how to structure this best is quite subjective. Based on that, read the paragraphs below with an implied "IMHO". Here is my proposal for a simple solution that should get you going.
I'll stick with your naming to keep things consistent. Even though I don't like the name MaterialTexture for this class. In the context of OpenGL, the name suggests that the class encapsulates a texture, which it's not.
First of all, classes should have constructors that initialize all members. This makes sure that even if the class is not used as expected, no class member is ever in an uninitialized state, which could otherwise result in undefined behavior. I agree that having a constructor with 12 float arguments would be awkward in this case. I would have a default constructor that initializes all members to a reasonable default, e.g. matching the defaults of the old fixed pipeline:
MaterialTexture::MaterialTexture()
{
diffuse[0] = 0.8f;
diffuse[1] = 0.8f;
diffuse[2] = 0.8f;
diffuse[3] = 1.0f;
ambient[0] = 0.2f;
ambient[1] = 0.2f;
ambient[2] = 0.2f;
ambient[3] = 1.0f;
specular[0] = 0.0f;
specular[1] = 0.0f;
specular[2] = 0.0f;
specular[3] = 1.0f;
}
Your setDiffuse(), setSpecular() and setAmbient() methods look fine.
Now the question is where you create the specific materials (plastic, metal). Using static methods in this class is one option, but I don't think it's a clean design. This class represents a generic material. Putting knowledge of specific materials in the same class mixes up responsibilities that should be separate.
I would have a separate class that provides specific materials. There's a lot of options on how that could be designed and structured. The simplest is to have methods to create the specific materials. For a slightly nicer approach that allows you to add materials without changing any interfaces, you could reference them by name:
class MaterialLibrary
{
public:
MaterialLibrary();
const MaterialTexture& getMaterial(const std::string& materialName) const;
private:
std::map<std::string, MaterialTexture> m_materials;
}
MaterialLibrary::MaterialLibrary()
{
MaterialTexture plastic;
plastic.setDiffuse(...);
...
m_materials.insert(std::make_pair("plastic", plastic));
MaterialTexture metal;
metal.setDiffuse(...);
...
m_materials.insert(std::make_pair("metal", metal));
}
const MaterialTexture& MaterialLibrary::getMaterial(const std::string& materialName) const
{
return m_materials.at(materialName);
}
You could easily change this to read the list of materials from a configuration file instead of having it in the code.
Now you just need to create and use one instance of MaterialLibrary. Again, there's a multiple ways of doing that. You could make it a Singleton. Or create one instance during startup, and pass that instance to everybody who needs it.
Once you have a MaterialLibrary instance lib, you can now get the materials:
const MaterialTexture& mat = lib.getMaterial("plastic");
You could get fancier and make the MaterialLibrary more of a factory class, e.g. a Template Factory. This would separate the responsibilities even further, with the MaterialLibrary only maintaining a list of materials, and providing access to them, but without knowing how to build the list of specific materials that are available. It's your decision how far you want to go with your abstraction.
You simply cannot call a function "in the middle of nowhere". This has nothing to do with namespaces. Consider this complete example:
void f() { }
f();
int main()
{
}
It won't compile.
A solution would be to add three different static member functions returning the three special instances, which may actually be created in another (private) static member function. Here is an example:
class MaterialTexture
{
private:
float diffuse[4];
float specular[4];
float ambient[4];
static MaterialTexture makePlastic()
{
MaterialTexture plastic;
plastic.setDiffuse(0.6, 0.0, 0.0, 1.0);
return plastic;
}
public:
// Three functions below set the values for data members above.
void setDiffuse(float R, float G, float B, float A);
void setSpecular(float R, float G, float B, float A);
void setAmbient(float R, float G, float B, float A);
static MaterialTexture &plastic()
{
static MaterialTexture plastic = makePlastic();
return plastic;
}
};
There's room for improvement, though, especially if you can use C++11:
Replace your raw arrays with std::array.
Consider using double instead of float.
Add a private constructor which allows you to get rid of the private static member functions and instead allows you to create the object directly.
Here is a complete improved example:
class MaterialTexture
{
private:
std::array<double, 4> diffuse;
std::array<double, 4> specular;
std::array<double, 4> ambient;
MaterialTexture(std::array<double, 4> const &diffuse, std::array<double, 4> const &specular,
std::array<double, 4> const &ambient) : diffuse(diffuse), specular(specular), ambient(ambient) {}
public:
// Three functions below set the values for data members above.
void setDiffuse(double R, double G, double B, double A);
void setSpecular(double R, double G, double B, double A);
void setAmbient(double R, double G, double B, double A);
static MaterialTexture &plastic()
{
static MaterialTexture plastic(
{ 0.6, 0.0, 0.0, 1.0 },
{ 0.0, 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0, 0.0 }
);
return plastic;
}
};

How do I create an immutable static public object within a class?

I have a class Color that holds values for the red, green, blue, and alpha channels of a color. The class constructor lets you create a new color by specifying values for the four channels. However, for convenience, I would also like to have some "premade" colors available for the programmer. For example instead of having something like
DrawBox(new Color(255, 0, 0));
you would be able to say
DrawRectangle(Color::Red);
Where Color.Red is an instance of Color that lives inside the Color class. How can I declare these instances of Color inside the Color class? I'm sure there's a name for this technique, but I had no idea what search terms to use when I was looking for help online.
I'm not using any built-in or publicly-available classes or libraries because this is part of a personal exercise in creating a basic graphics stack.
Thanks for your help!
First of all, avoid using new. You could use Color as simple value-type.
Now as an answer to your question, yes, you can do that as:
//color.h
typedef unsigned char byte;
class Color
{
public:
//declaration
const static Color Red;
const static Color Green;
const static Color Blue;
public:
Color(byte red, byte green, byte blue);
};
//define the static members in color.cpp file
#include "color.h"
const Color Color::Red(255,0,0);
const Color Color::Green(0,255,0);
const Color Color::Blue(0,0,255);
Then use Color::Red as you want to use.

Global variable in C++

I'm writing c++ project, which contains several classes. I created .h file named Position.h, with one array and one function:
class Position
{
public:
Coord positions[25];
public:
void setPos(int index, double x, double y)
{
positions[index].x = x;
positions[index].y = y;
}
};
I want to set values in this array from another classes, so every class in this project will see the same values.
I included "Position.h" in other classes, but i can't access the "positions" array.
Anyone can help me plz??
Just chnage the statement :
Coord positions[25];
to
static Coord positions[25];
also change void setPos
to
static void setPos
while accesing the array ,access it as:
Position::positions[any value]
But before accessing the array,make sure you call the function setPos
positions is a member variable associated with a class instance, and therefore not a global. You can make it similar to a global by making it static. Doing so, it will become a class-scoped variable, and not bound to an instance.
You will need to define it in a single implementation file.
An even better alternative would be having an std::vector<Coord>.
As suggested by others, you can make the members static.
You can also create an instance of the Position class as a global variable, and use that:
Position globalPosition;
void function_using_position()
{
globalPosition.setPos(0, 1, 2);
}
int main()
{
function_using_position();
}
Or make it a local variable, and pass it around as a reference:
void function_using_position(Position &position)
{
position.setPos(0, 1, 2);
}
int main()
{
Position localPosition;
function_using_position(localPosition);
}

Accessing to enum values by '::' in C++

I have class like following:
class Car
{
public:
Car();
// Some functions and members and <b>enums</b>
enum Color
{
Red,
Blue,
Black
};
Color getColor();
void setColor(Color);
private:
Color myColor;
}
I want to:
access to Color values as Color::Red. It is really hardly to understand code when Car::Red is used, when class have a lot enums, subclasses etc.
use type Color as function argument or return value
use variable type Color in switch
I know 3 partial solutions:
Using embedded class Color and enum in it
Using embedded namespace Color and enum in it
Using enum class
1 and 2 solutions solves a Color::Red accession problem, but I can't use functions like Color getColor() and void setColor(Color).
3 solution has a problem: VS2010 doen't support enum class. GCC v.4.1.2 doesn't support it too. I don't know about later versions of gcc.
Yes, I'm working on cross-platform project.
I have found this solution, but it seems ... heavy.
I hope somebody can help me here :)
In current C++ (i.e. C++11 and beyond), you can already access enum values like that:
enum Color { Red };
Color c = Color::Red;
Color d = Red;
You can go further and enforce the use of this notation:
enum class Color { Red };
Color c = Color::Red;
// Color d = Red; <-- error now
And on a sidenote, you now define the underlying type, which was previously only possible with hacky code (FORCEDWORD or so anyone?):
enum class Color : char { Red };
Name the enum inside the nested class (as example one):
class Car
{
public:
struct Color
{
enum Type
{
Red,
Blue,
Black
};
};
Color::Type getColor();
void setColor(Color::Type);
};
When I want to do something like this I tend to use a namespace and a typedef outside of th namespace (though usually I'm doing this globally rather than inside a class). Something like this:
namespace colors
{
enum Color
{
Red,
Blue
...
}
}
typedef colors::Color Color;
This way you use the namespace to get at the actual colors, but the Color type itself is still globally accessible:
Color myFav = colors::Red;