so say I have something like this:

#include<iostream>

class A{

public:
	void setErrorMessage(char*);
	
}

void A::setErrorMessage(char* errMessage){

	// code here to set B::errMsg
	
}

class B{

public:
	A someObject[3];
	char* errMsg;
	
}

int main(int argc,char** argv){

	B something;
	B another;
	something.someObject[2].setErrorMessage("BIG ERRAR!");
	another.someObject[0].setErrorMessage("everything's okay!");
	
	cout<< something.errMsg<< endl;
	cout<< another.errMsg<< endl;
	
	return 0;
	
}

This is of course a useless code, but I'm using something like it in a larger situation...
Anyways, if I create a class A, and then use it to create an object in another class B, and then create an object C of class B--C.A generates an error and needs to set the (not static--otherwise it'd be easy) error message to C, and specifically the object C, and leave the errMsg variable of other instances of B alone.

Can it be done?

Recommended Answers

All 12 Replies

Well . I think :

when the compiler starts reading your code.

it goes into the (set error message function) and then looks at a class B .. which doesnt exist until then .
---------------------------------------------------
Secondly. There is no need for the class A to be in class B. So i guess you cannot get back from the functions of A to the parent in B

but there is a need for class A to be in class B

What's a problem? Class B must be known before A::setErrorMessage definition - that's all. Collect both class definitions in .h file, include it in .cpp file with class A implementation - or simply move up class B definition in your main module just before A::setErrorMessage definition...

Apropos, you have posted "useless" snippet but on the other hand this code is an excellent example of a very bad class design ;)

lol what's bad about it? I put it in that order because class A has to be known before I can declare an object of type A in class B, the classes need to interact with each other, that is my problem.

The main use I need is this,

something.someObject[2].setErrorMessage("BIG ERRAR!");
	another.someObject[0].setErrorMessage("everything's okay!");
	
	cout<< something.errMsg<< endl;
	cout<< another.errMsg<< endl;

because although my class is obviously not going to have a setErrorMessage function, if class B generates an error, I don't want to have to cycle through all instances of A.B to find an error code--so I was going to try and get A.B[x] to set A.errorMessage so that I could just check to see if there were any error messages within the system. I suppose it would be much easier if I just set a static or global variable, although if there were multiple instances of class A in use this would be confusing.

In my example code above,
if I called something.someObject[2].setErrorMessage("BIG ERRAR!"); ,
and then in A::setErrorMessage(char*), used the this operator, would "this" refer only to someObject[2] or to something::someObject[2]?
could I access the "something" portion of it?
If this is a pointer to the object which called the class, how can I get a pointer to the object containing the object calling the class ("something")? And, specifically the object ("something"), not the object's class containing the object calling the class ("B")--but I don't know why the pointer would exist that way anyways...

Let's come back to your object model design.

Who is a target of an error message which a class A object setErrorMessage member function registered? If it's this object, where is this message container? No such containers in class A.

Now let's consider class B. Semantically it's a container of three class A objects + a single error message pointer. By the way, the original post title was incorrect: no parent/child relations between your A and B classes. The class B "has" A (parent/child corresponds to "is_a" predicate). Any object of class B contains some objects of class A. No any special mechanics in C++ for such relation: container elements do not have any special info about containers where they exist. An example:

B b1; // have b1.someObject[0..2] - three class A objects
B b2; // have b2.someObject[0..2] - yet another 3 class A objects
A a;	// lonely A object (seventh)

All seven class A objects do not know where they live. Suppose you invent some method to save b1.someObject[0].seErrorMessage("b1.[0]") argument in b1 container object. But where is a target of a.setErrorMessage("for orphans only") message?

I think you need redesign this error message register mechanics. For example, if you want to save container elements error messages in the container, link contained elements with a container explicitly (add a pointer to a container in class A with null pointer for lonely objects - or what else).

sounds perfect... how would I declare a pointer in the A class though?
Like, would I just go B &errorTarget; ?
or would I use the * operator? The most I've really worked with pointers so far is in C-style strings, really... Also, is which class I define first still an issue? Is there a way to declare the two classes at the top of the code and then define them after? Since each class has to call the other, there isn't really a way for them both to be aware of each other at compile time is there?

This is what I've tried...

#include<iostream>

using namespace std;

class B{

public:
	class A{
		B errorTarget;
		
	public:
		A(B&);
		//A();
		void setErrorMessage(char*);
	} aObj[3] (this);
	//A aObj[3] (this);
	char errorMessage[80];

};

B::A::A(B& errTarget){

	&errorTarget=&errTarget;

}

void B::A::setErrorMessage(char* newErrMsg){

	int i=0;
	while(newErrMsg[i]!='\0'&&i<80){
		errorTarget.errorMessage[i]=newErrMsg[i];
	}
	errorTarget.errorMessage[i]='\0';
	
}

int main(int argc,char** argv){

	B bObj1;
	B bObj2;
	
	bObj1.aObj[1].setErrorMessage("hallo!");
	bObj2.aObj[2].setErrorMessage("omgomgomg");
	
	cout<< bObj1.errorMessage<< endl;
	cout<< bObj2.errorMessage<< endl;
	
	return 0;
	
}

but I get a whole bunch of error messages...

C:\c>gpp tecls.cpp -o tecls.exe
tecls.cpp:9: error: field `errorTarget' has incomplete type
tecls.cpp:15: error: expected identifier before "this"
tecls.cpp:15: error: expected `,' or `...' before "this"
tecls.cpp:15: error: new types may not be defined in a return type
tecls.cpp:15: note: (perhaps a semicolon is missing after the definition of `B::
A')
tecls.cpp:15: error: ISO C++ forbids declaration of `parameter' with no type
tecls.cpp:15: error: declaration of `aObj' as array of functions
tecls.cpp: In constructor `B::A::A(B&)':
tecls.cpp:23: error: `errorTarget' was not declared in this scope
tecls.cpp: In member function `void B::A::setErrorMessage(char*)':
tecls.cpp:31: error: `errorTarget' was not declared in this scope
tecls.cpp:33: error: `errorTarget' was not declared in this scope
tecls.cpp: In function `int main(int, char**)':
tecls.cpp:42: error: 'class B' has no member named 'aObj'
tecls.cpp:43: error: 'class B' has no member named 'aObj'
tecls.cpp:50:2: warning: no newline at end of file

C:\c>

Think about:

/// The last cry container interface.
class MsgSink {
public:
    virtual ~MsgSink() {}
    virtual void saveMessage(const char* pmsg) = 0;
};

class A {
public:
    A():pSink(0) {}
    /// Need explicit to prevent strange casts
    explicit A(MsgSink& sink):pSink(&sink) {}
    explicit A(MsgSink*psink):pSink(psink) {}
    /// It's impossible to initialize array elements
    /// via constructor so we need a special method:
    void bind(MsgSink* psink) { pSink = psink; }
    void bind(MsgSink& sink)  { pSink = &sink; }
    void error(const char* pmsg) {
        if (pmsg && pSink)
            pSink->saveMessage(pmsg);
    }
private:
    MsgSink* pSink;
};
/// A very strange A objects shell
class B: public MsgSink {
public:
    B();
    A   aaa[3];
    const char* getLastMsg() const { return lastMsg.c_str(); }
    void saveMessage(const char* pmsg) {
        if (pmsg)
            lastMsg = pmsg;
        else
            lastMsg.clear();
    }
private:
    /// Think about std::vector to save a log...
    std::string lastMsg;
};

B::B() 
{   // Bind aaa elements to this object.
    for (size_t i = 0; i < sizeof aaa/sizeof*aaa; ++i)
        aaa[i].bind(this);
}

well it works really well but there is some syntax here that I don't completely understand... virtual void saveMessage(const char* pmsg) = 0; virtual means that the child class will inherit this member right? Also, what is the =0 for? A():pSink(0) {} The constructor, but what does the :pSink(0) end of it do?

explicit A(MsgSink& sink):pSink(&sink) {}
    explicit A(MsgSink*psink):pSink(psink) {}

what are these doing, and why do you need to use one for MsgSink& and MsgSink*? if (pmsg && pSink) if this is testing for pmsg and pSink to be initialized, why wouldn't pmsg be initialized if it's a function argument?


Anyways I'm playing with the code to try and understand it... Thanks for your patience

>virtual means that the child class will inherit this member right?
Nope. The child class will inherit any member function(s) of its parent(s). You know (I hope) that it's possible to access objects of derived classes via pointers or references to the base class. When you call virtual member function in such a way, the "most derived" member function will been called.

I have declared saveMessage as a virtual because I hope that the "real" child of the class MsgSink implements its own saveMessage function to get and save correspondent argument. Moreover, I declare this function as a pure virtual (see =0 instead of the function body). Now derived (from MsgSink) classes must define this function to be concrete classes (i.e. have objects). A class with pure virtual function(s) called abstract class, it's impossible to instantiate it (impossible to define an object of this class). It's an interface (with derived classes) only. I want to define a proper message reciever interface then use it in class A. No matter who and where intercept my messages from class A object. In other words, the class A now is absolutely independed of the class B or any other class which will been derived from MsgSink abstract class.

About explicit keyword...
You may declare these constructors without explicit keyword. The C++ standard:

A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters to the type of its class. Such a constructor is called a converting constructor.

In our case it's a senseless conversion so I declare these constructors as explicit ones and now only an explicit cast expression converts a pointer (or a reference) to MsgSink to A. Obviously, you (and me) will never write this cast expression. Now we will have compiler error if (for example) we will pass (by mistake) a pointer to MsgSink instead of class A object in a function call...

>if this is testing for pmsg and pSink to be initialized, why wouldn't pmsg be initialized if it's a function argument? if (pmsg && psink) is a brief (and legal) form of if (pmsg != 0 && psink != 0) . Most of new age programming style purists condemn such a form of null pointer testing but I think it's a very useful and clear construct (may be valid/bad pointer test: good/bad ... yes/no ... true/false). I like C and C++ for such idioms ;)). So it does not matter to initialized/not initialized test. I want to dereference pSink in the next statement but it's impossible if pSink == 0. I don't want that null pointer pmsg argument discards the last message passed to the MsgSink receiver. That's all.

More about virtual (and pure virtual) functions:
http://www.exforsys.com/tutorials/c-plus-plus/c-virtual-functions.html
http://www.exforsys.com/tutorials/c-plus-plus/c-pure-virtual-function-and-base-class.html
Use Google search for more info on this topic...

Good luck!

awesome, thanks a lot for your help

I already marked it as solved, but just letting you know I got it all working, and I understand all the code now--thanks for the help, I learned a lot more about classes.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.