I have a struct that multiple classes can access and edit. So I created this struct's object as static in class and created a get method.
In Class1.cpp:
#include "Class1.h"
static MyStruct struct;
MyStruct* Class1::get_my_struct()
{
return &struct;
}
I thought of creating this class`s object as a singleton to guarantee that this struct can be accessed through a single object.
In Class2.cpp:
#include "Class2.h" //Class1.h file included in this file.
void Class2::log_value()
{
Class1& singleton_obj_cls1 = Class1::getObject(): //return singleton object
singleton_obj_cls1 .get_my_struct().tempr_val=log_temp_val(); //log this value of struct by class 2 method
}
void Class2::change_value()
{
Class1& singleton_obj_cls1 = Class1::getObject():
//Do I have to get the singleton object for different methods even though they are in the same class?
//Can a singleton object get in one place in class and the whole class use it as a class member?
singleton_obj_cls1 .get_my_struct().tempr_val=45;
singleton_obj_cls1 .get_my_struct().x_val=66 ;
}
I have class 3 class that uses both class1 and class 2.By the way, I changed class2`constructor to a singleton.
In Class3.cpp:
#include "Class3.h" //Both Class1.h and Class2.h file included in this file.
void Class3::calculate_value()
{
Class1& singleton_obj_cls1 = Class1::getObject():
Class2& singleton_obj_cls2 = Class2::getObject():
singleton_obj_cls2.log_value();
singleton_obj_cls1.get_my_struct().pressure_value=300;
}
My third question is, Is there a better design method that you can fix instead of getting singleton objects in multiple places before using each struct or should I create the object once in the top class and give it as parameters to all 100 methods of perhaps 20 different classes that should have access to this struct?
Do I have to get the singleton object for different methods even though they are in the same class?
Can a singleton object get in one place in class and the whole class use it as a class member?
Use a member variable in your header file and initialize it in the constructor member initializer list:
Example Class2.h
#include "Class1.h"
class Class2 {
//...
private: // maybe public/protected to access from other classes
Class1& m_singleton_obj_cls1;
};
Example Class2.cpp
#include "Class2.h"
Class2::Class2()
: m_singleton_obj_cls1(Class1::getObject()) {
}
//...
Related
I have a class Dmx with a nested class touchSlider. So before I had these classes in my main.cpp file and just created an object array of touchSlider within the Dmx class and it worked properly. How can I implement this here, with different header files? The compiler gives an error message: invalid use of incomplete type 'class Dmx::touchSlider' The object array is: touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};
dmx.h
// dmx.h
#ifndef dmx_h
#define dmx_h
class Dmx {
public:
byte number;
Dmx(byte numberA) {
number = numberA;
}
void settingsDisplay();
class touchSlider; // declaration of nested class
touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};
};
#endif
touchSlider.h
// touchSlider.h
#ifndef touchSlider_h
#define touchSlider_h
#include "dmx.h"
class Dmx::touchSlider{
private:
int pos;
public:
touchSlider(int posA){
pos = posA;
}
void printChannel();
};
#endif
main.cpp
// main.cpp
#include "dmx.h"
#include "touchSlider.h"
Dmx dmx[10] = {Dmx(1), Dmx(2),Dmx(3), Dmx(4), Dmx(5), Dmx(6), Dmx(7), Dmx(8), Dmx(9), Dmx(10)};
void Dmx::settingsDisplay() {
// do something
}
void Dmx::touchSlider::printChannel() {
// do something
}
My previous code (that worked great) where both classes where in the same file looked like this:
class Dmx {
public:
byte number;
Dmx(byte numberA) {
number = numberA;
}
void channelDisplay(){
}
void settingsDisplay(){
}
class touchSlider{
private:
int pos;
public:
touchSlider(int posA){
pos = posA;
}
void setChannel(/* some arguments*/){
}
void printChannel();
}
};
touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};
};
Dmx dmx[10] = {Dmx(1), Dmx(2),Dmx(3), Dmx(4), Dmx(5), Dmx(6), Dmx(7), Dmx(8), Dmx(9), Dmx(10)};
To be able to create an array:
touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};
You need the class definition available, because the compiler needs to know
the size of the struct or class in use and
if there's a suitable constructor available.
You now have two options, either you provide the class definition in the header but implement the class within the source file like:
// header:
class Dmx
{
public:
// ...
class TouchSlider
{
public:
// only DECLARE here:
TouchSlider(int posA);
void setChannel(/* some arguments*/);
void printChannel();
};
};
// source:
Dmx::TouchSlider::TouchSlider(int posA)
: pos(posA) // note: prefer the initialiser list!
{ }
void Dmx::TouchSlider::setChannel(/* some arguments*/)
{
}
// ...
or you hide away the implementation as you intended, but then you need to allocate the memory dynamically (this is the PImpl idiom) – at best with help of a std::unique_ptr:
class Dmx
{
public:
// ...
private:
class TouchSlider; // just declare
std::unique_ptr<TouchSlider[]> sliders;
};
Important (see cppreference), though:
std::unique_ptr may be constructed for an incomplete type T, such as to facilitate the use as a handle in the pImpl idiom. If the default deleter is used, T must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset member function of std::unique_ptr.
I.e. you cannot implement e.g. your class' destructor in the header file either but need to do so in the source file as well – after the nested class' full definition – alike any function that might re-assign another array.
The std::unique_ptr avoids necessity of manual memory management (see rules of three/five), on the other hand the class gets non-copiable (but you can work around by providing your own custom copy constructor and assignment while defaulting the move constructor and assignment).
In order to create an array of touchSlider the compiler needs a definition of the touchSlider class. So as written this will not work.
In the code given
touchSlider slider[10] = {50,130,210,290,370,50,130,210,290,370};
the complier needs to know how big a touchSlider object is so it can allocate enough memory for a Dmx object. It also needs to know that a touchSlider can be constructed from an int. Both these things require the full definition of touchSlider.
Now maybe you can use some variation to achieve whatever your goal is, but without more details it's hard to suggest anything.
I am trying to have two classes in C++ - class1, class2. I want class2 to contain an instance of class1 and class1 to have a shared_ptr to the class2 – a pointer to the object, in which it is contained.
So I have following 4 files:
class2.hpp
#include "class1.hpp"
#include <vector>
class class2 {
friend class1;
private:
class1 data;
std::vector<int> numbers;
public:
class2();
};
class2.cpp
#include "class2.hpp"
class2::class2() : data(std::shared_ptr<class2>(this)){}
class1.hpp
#include <memory>
class class2;
class class1 {
std::shared_ptr<class2> ptr;
class1(std::shared_ptr<class2> ptr);
void add_item(int i);
};
and class1.cpp
#include "class1.hpp"
class1::class1(std::shared_ptr<class2> ptr) {
ptr = ptr;
}
void class1::add_item(int i) {
ptr->add_item(6); //Member access into incomplete type 'std::__1::shared_ptr<class2>::element_type' (aka 'class2')
}
I am getting the error in function add_item. I think that it has something to do with the forward declaration of class2.
I found this related topic, but there they dont split the files into header file.
error: member access into incomplete type : forward declaration of
If I understand well, I should put the function add_item after definition of class2, but I dont how to solve it, if I want to have the files splitted like this. Is it possible?
Please note, that I am trying to solve this in bigger project, this is very simplified.
Thanks is advance for any answer.
Forward declare class1 in class2.hpp and include class2.h in class1.cpp.
class2.hpp:
//#include "class1.hpp" // REMOVE!
#include <vector>
class class1; // ADD
class class2 {
...
class2.cpp:
#include "class2.hpp"
#include "class1.hpp" // ADD
class1.hpp:
#include <memory>
class class2; // OK
class1.cpp:
#include "class1.hpp"
#include "class2.hpp" // ADD
class1::class1(std::shared_ptr<class2> ptr) {
ptr = ptr;
}
I want class2 to contain an instance of class1 and class1 to have a shared_ptr to the class2 – a pointer to the object, in which it is contained.
No, you should not want that. There is no reason for a sub-object to own (even in shared capacity) their super object.
Furthermore, you cannot access members of an incomplete class. You must define the class first.
I create a basic IBasic interface with a static field
class IBasic
{
public:
IBasic();
virtual ~IBasic();
static std::vector< std::vector<char> > Field;
};
from which the Inherit class is inherited:
class Inherit : public IBasic
{
public:
Inherit(int);
~Inherit();
void Foo();
};
The Inherit class makes some manipulations with Field static member in constructor/or member function.
In order to create an instance of the Inherit class, we need to explicitly declare a static field in the main.cpp before the main function:
#include "Basic.h"
#include "Inherit.h"
std::vector< std::vector<char> > IBasic::Field;
int main()
{
Inherit(10);
return 0;
}
The questions are:
In what namespace does the static method actually exists (global?)? Because I know that static field/function is not a class member in fact.
Is there another way to declare this static method, for example, in a
class file, inside a main function, or through creation unnamed namespace? Is it only one right variant?
How is right? What should be considered first of all?
A static member of a class is a member of its class (that's a tautology) and its class namespace (a class is a namespace). It is not a nember of any other namespace.
A non-const static data member of a class must be defined exactly once in a program, outside of any class, in the same namespace its class is defined in (a global namespace in your case). A header file is inappropriate place for such declaration. It is normally placed in an implementation .cpp file that goes together with the header file.
Having said that, an interface should not have any static data members, much less public ones. It is most likely a grave design error.
In what namespace does the static method actually exists (global?)? Because I know that static field/function is not a class member in fact.
It is declared in scope of the class. In fact the static variable is a class member, your assumption is wrong.
Is there another way to declare this static method, for example, in a class file, inside a main function, or through creation unnamed namespace? Is it only one right variant?
The usual way is to define it in the translation unit that contains the function definitions for the class.
How is right? What should be considered first of all?
There's no right or wrong way, but as mentioned definition in the same translation unit as the class function definitions is the usual way.
Here's an example usage of a static member without any inheritance.
SomeClass.h
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
class SomeClass {
private:
int x;
public:
static SomeClass* const get(); // Needed For Using class to get this pointer
SomeClass();
int getX() const { return x; }
void setX( int val ) { x = val; }
};
#endif // SOME_CLASS_H
SomeClass.cpp
#include "SomeClass.h"
static SomeClass* s_pSomeClass = nullptr;
SomeClass::SomeClass() {
s_pSomeClass = this;
}
SomeClass* const SomeClass::get() {
if ( nullptr == s_pSomeClass ) {
// throw exception
}
return s_pSomeClass;
}
Another class using above class as a static member
OtherClass.h
#ifndef OTHER_CLASS_H
#define OTHER_CLASS_H
class SomeClass; // Forward Declaration
class OtherClass {
private:
static SomeClass* pSomeClass; // The Static Member to this class
int y;
public:
OtherClass();
int getY() const { return y; }
void setY( int val ) { y = val; }
void useSomeClassToSetY();
};
#endif // OTHER_CLASS_H
OtherClass.cpp
#include "OtherClass.h"
#include "SomeClass.h"
SomeClass* OtherClass::pSomeClass = nullptr;
OtherClass::OtherClass() {
if ( nullptr == pSomeClass ) {
pSomeClass = SomeClass::get();
}
}
void OtherClass::useSomeClassToSetY() {
// First Set X To Some Value:
pSomeClass->setX( 10 ); // Use of Static Member
y = pSomeClass->getX(); // Use of Static Member
}
Static members still belong to the class, but they have static storage.
I've two different classes (class1 class2) both of them have their own header and cpp files. Class2 has included the header of class1. Class1 has two structures which are public.
I want to call a method from class2 in class1 and to pass two pointers pointing on the structures.
The call of the method from class2 in class1. (obj is an object of class2 in class1):
obj.routine(ip_s.c_str(), &NLP_data_recv, &recv_data_data); //write to harddrive
Following the declaration of the method in class2:
int routine(std::string raw_data_re, struct NLP_data_header_package *Header_data, struct NLP_data_data_package *Data_data);
The following Error occurs:
“argument of type ""com::NLP_data_data_package *"" is incompatible with parameter of type ""NLP_data_data_package *""
How can I solve this problem? Thank you.
EDIT: Additional code:
class com header(class1):
#ifndef COM_H
#define COM_H
//...
#include "Dateiverwaltung.h"
//...
class com
{
private:
Dateiverwaltung obj;
//...
public:
int run(void);
com(std::array<std::string,TWO> socket);
~com();
struct NLP_data_header_package
{
//...
}NLP_data_recv;
struct NLP_data_data_package
{
//...
}recv_data_data;
class com cpp (class1)
//...
if (recv_command == DATA_COMMAND)
{
obj.routine(ip_s.c_str(), &NLP_data_recv, &recv_data_data); //write to harddrive
obj.ext_close_file();
}
//...
class Dateiverwaltung header(class2)
#ifndef DATEIVERWALTUNG_H
#define DATEIVERWALTUNG_H
//...
#include "communication.h"
//...
public:
Dateiverwaltung(char* directory_global_re);
~Dateiverwaltung();
int routine(std::string raw_data_re, struct NLP_data_header_package *Header_data, struct NLP_data_data_package *Data_data);
int ext_close_file(void);
//...
class Dateiverwaltung cpp (class2)
//...
int Dateiverwaltung::routine(string raw_data_re, struct NLP_data_header_package *Header_data, struct NLP_data_data_package *Data_data)
{
//...
The error says there's a "com::NLP_data_data_package"
and a "NLP_data_data_package"
That's two different classes (for the compiler), since they seem to be defined in different namespaces, namely com and the default namespace.
I am trying to implement the following class. However, when I try to instantiate an object of the class within its definition and pass "0" as value to initialize the object, i get an error:
"a type specifier is expected".
Can anyone explain how can i remove this error?
class MessageType
{
public:
static const MessageType msgEvent(0);
private:
MessageType();
virtual ~MessageType();
MessageType(int);
};
You need to initialize(define) it outside the class definition in a cpp file.
MessageType const MessageType::msgEvent;
However, Your intent in doing so is not very clear. Are you trying to implement a Singleton Pattern, probably this sample implementation might help, I leave it to you to decide, whether you really need a singleton, inspite of its disadvantages:
//MessageType.h
#include <boost/noncopyable.hpp>
class MessageType: private boost::noncopyable
{
public:
static MessageType* instance();
private:
MessageType();
~MessageType();
static bool g_initialised;
// static initialisation
static MessageType g_instance;
// dynamic initialisation
};
// MessageType.cpp
#include "MessageType.hpp"
#include <ostream>
#include <iostream>
#include <cstring>
bool MessageType::g_initialised;
// static initialisation
MessageType MessageType::g_instance;
// dynamic initialisation
MessageType::MessageType()
{
g_initialised = true;
}
MessageType::~MessageType()
{
g_initialised = false;
}
MessageType* MessageType::instance()
{
return g_initialised ? &g_instance : 0;
}
You can only initialize static member variables in the definition if they are of int type.
class MessageType
{
public:
static int sCount = 0; // That is fine.
static std::string sLogName; // That is fine.
static std::string sLogName("log.txt"); // Fail!
};
There's no way around this rule. If you want to initialize a static member variable, then you have to do it in the cpp:
std::string MessageType::sLogName("log.txt"); // fine, in the cpp.
This same rule applies directly to your MessageType instance, and has nothing to do with the fact that the class is of it's own type.