'C++'에 해당되는 글 2건

  1. 2008.02.21 [C++] in/out parameter passing by reference? And your preference? by Dansoonie
  2. 2008.02.19 [C++] How to make Circular Dependency work??? by Dansoonie
Until I started to work, there wasn't much chance for me to look at how real world code really works. In other words, I programmed in my own fashion and I only had to use my own codes. However, I had to write MFC applications as I started to work. I realized that many of the methods for MFC were written and used very differently from how I used to write methods.

When passing by parameter to a function in an in/out fashion, I usually use the following function signature.

// Foo case: parameter is passed by reference
void Foo(int& a);

But, the functions or methods written for MFC usually use the following signature for in/out parameters.

// Bar case: parameter is a pointer type
void Bar(int* a);

So, what's the difference?
Here is my explanation according to my opinion. The function signature that I usually use for in/out parameters explicitly shows that it is passed by reference like the Foo case. I say "explicit" because you can know the parameter is passed by reference just by looking at the function signature. However, in the Bar case, the parameter is passed by reference implicitly by passing a pointer type. Even though they both have the same affect on the parameter, the Bar case does not necessarily mean that the parameter is passed by reference. They both have the same affect on the parameter, but keep in mind that all parameters are passed by value in C++. Therefore, passing a parameter by reference only works by passing an address of a variable (or an object). For that reason, I am saying that passing a pointer to a function does not necessarily mean that you want the parameter to work in an in/out manner.

Sometimes you simply want to pass a pointer. In that case you should limit the side affect on the parameter by using the const keyword. So, if that is the case function Bar should be written

void Bar(const int* const a)

but let's don't discuss that here.


On the other hand, the situation looks slightly different in the client code like the following.

int b;
Foo(b);     // calling Foo(int& a)
Bar(&b);   // calling Bar(int* a)

By looking at the code, you won't be able to tell whether b is passed by value or reference for Foo. Since the parameter passing scheme of Foo is indeterminable in the client code, I personally think that using a pointer type for in/out parameter is better to use than passing a parameter to a function by reference explicitly in the function signature (in other words Bar is better than Foo). Using the '&' to declare the parameter to be passed by reference in the function signature makes the intention clear in the function signature itself only. But by using a pointer type parameter, you can at least guess that the parameter is in/out by looking at the function signature and maybe it becomes clearer when you look at how it is used the client code. Besides, as I mentioned in the colored quoted section above, if you want to pass a pointer to the function and avoid side affects, you should use the const keyword.

So, my conclusion...
For code readability issues, I personally think that functions that require in/out parameters should be written in the Bar way rather than the Foo way.




Posted by Dansoonie
It's been a while since I have learned C++ from school. The last time I heard about circular dependency in C++ was from my sophomore year in college. Yesterday, I was having trouble making circular dependency to get working. I decided to post about how I solved the problems I had considering that circular dependency isn't a situation you encounter very often. I usually get rusty on things I don't do often. Hopefully, many people are like me and some may benefit from this post sometime later.


While at work designing an application, I encountered a situation where two classes had attributes of their own referring to another class in the following manner.
사용자 삽입 이미지
I recognized that this resulted in a circular dependency and included a forward declaration in the header file of each class for the class that it was referring to. So the header file for each class resulted in the following.
 
// A.h
class B;   // forward declaration for class B
class A
{
    private:
       B* pB
    public:
       ...
};

// B.h
class A;    // forward declaration for class A
class B
{
    private:
       A a;
    public:
       ...
};
However, I got a compile error indicating that class A and B were not defined. It was weird at first because I thought I got my circular dependency problem solved. I had no idea how to get around the compile error. My solution to this was to create another class to use it as a mediator for the establishing an associative relationship between class A and B. My new design was like the following.
사용자 삽입 이미지
I was stupid enough to think that this new design will avoid the circular dependency relationship. But after another build of my application, I figured that this also results in a circular dependency. If you look carefully at the #include statements in each header file for class A, B, and C,
    - A.h includes C.h
    - C.h includes B.h
    - B.h includes A.h
, but then B must compile A.cpp and A cannot be compiled because C and B has not been compiled. Therefore, class A is not defined and the circular dependency prevents the code to be compiled in spite of the forward declarations.

At this point, I realized that class A does not require C.cpp to be compiled. This is because that  class A refers to class C with a pointer. As you all know, pointers are usually a 4 byte (32 bit) integer and as long as the type of the pointer is specified, the code compiles. From what I have just realized, I decided to change my design like the following.
사용자 삽입 이미지
I could have gotten rid of class C but I kept it for another good reason (design issue in my application). As I changed all my inter class relationship into association, the code compiled as I expected and also worked fine.


The point I would like to make here is that it is important that you know that circular dependency only works only when classes are associated with each other based on pointers.

 Was this so obvious?
Posted by Dansoonie