[RESOLVED] using composition with scope issue
Following on from my console project I decided to change a line in my method for SetColor() in my color class that calls a public method in my ConsoleApp class. I now get an error 35 C:\vmAPI\color.cpp `GetWriteHnd' was not declared in this scope? I can resolve this by replacing GetWriteHnd() with GetStdHandle(STD_OUTPUT_HANDLE), but what if I really needed access to GetWriteHnd()?
As far as I know, the rule of thumb is a console has a color and a console has a cursor, thus I would place color and cursor class within the consoleApp class. I hope I am implementing this the correct way.
Here is the cut down version of the code that shows the issue (Which I have indicated):
Code:
//-----------------------------------------------------------------------------
// Project: vmAPI Framework
// Name: ConsoleApp.h
// Description: Console application class definition file
// Author: Gerald Bates
//-----------------------------------------------------------------------------
#ifndef __CONSOLE_APP_H__
#define __CONSOLE_APP_H__
#include <windows.h>
#include "color.h"
namespace vm {
class vmConsoleApp
{
public:
vmConsoleApp(int width = 79, int height = 49, char *consoleTitle = "NONAME");
~vmConsoleApp();
// Some WIN32 API functions need to use these handles
HANDLE GetWriteHnd() const;
HANDLE GetReadHnd() const;
HANDLE GetErrorHnd() const;
void SetColor(int fg, int bg = BLACK) { cColor.SetColor(fg, bg); }
private:
HANDLE m_hOut; // Handle to Write to the console
HANDLE m_hIn; // Handle to Read from the console
HANDLE m_hError; // Handle to std Error - directs to std out ?
int m_nLeft, m_nTop, m_nRight, m_nBottom; // Console size
char *m_pchConsoleAppTitle; // Console title
int SetWriteHnd();
int SetReadHnd();
int SetErrorHnd();
int CreateConsoleApp();
int SetConsoleAppTitle();
vmColor cColor;
};
} // namespace vm
#endif // __CONSOLE_APP_H__
Code:
//-----------------------------------------------------------------------------
// Project: vmAPI Framework
// Name: ConsoleApp.cpp
// Description: Console application class impementation file
// Author: Gerald Bates
//-----------------------------------------------------------------------------
#include <iostream>
#include "consoleApp.h"
using namespace vm;
//-----------------------------------------------------------------------------
// Function/Method: vmConsoleApp(int, int, char *)
// Description: Console application class constructor
// Return: N/A
//-----------------------------------------------------------------------------
vmConsoleApp::vmConsoleApp(int width, int height, char *consoleTitle)
: m_nLeft(0), m_nTop(0), m_nRight(width), m_nBottom(height),
m_pchConsoleAppTitle(consoleTitle)
{
SetWriteHnd(); // Obtain and set the standard output handle
SetReadHnd(); // Obtain and set the standard input handle
SetErrorHnd(); // Obtain and set the standard error handle
// If we don't have a valid output/input HANDLE, don't create a console app
if((GetWriteHnd() != INVALID_HANDLE_VALUE && GetWriteHnd() != NULL) &&
(GetReadHnd() != INVALID_HANDLE_VALUE && GetReadHnd() != NULL) )
CreateConsoleApp();
}
//-----------------------------------------------------------------------------
// Function/Method: ~vmConsoleApp()
// Description: Console application class destructor
// Return: N/A
//-----------------------------------------------------------------------------
vmConsoleApp::~vmConsoleApp() { }
//-----------------------------------------------------------------------------
// Function/Method: SetWriteHnd()
// Description: Set the standard output handle - Write
// Return: If SetWriteHnd() is successful then EXIT_SUCCESS is
// returned, otherwise EXIT_FAILURE is returned
//-----------------------------------------------------------------------------
// Note: If the function GetStdHandle() fails, the return value is
// INVALID_HANDLE_VALUE. To get extended error information,
// call GetLastError(). If an application does not have
// associated standard handles, such as a service running on
// an interactive desktop, and has not redirected them, the
// return value is NULL.
//
// MSDN - http://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx
//-----------------------------------------------------------------------------
int vmConsoleApp::SetWriteHnd()
{
m_hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if(m_hOut == INVALID_HANDLE_VALUE || m_hOut == NULL) {
std::cout << "Error occurred obtaining the standard output handle."
<< std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
//-----------------------------------------------------------------------------
// Function/Method: SetReadHnd()
// Description: Set the standard input handle - Read
// Return: If SetReadHnd() is successful then EXIT_SUCCESS is
// returned, otherwise EXIT_FAILURE is returned
//-----------------------------------------------------------------------------
// Note: See SetWriteHnd() above for more details
//-----------------------------------------------------------------------------
int vmConsoleApp::SetReadHnd()
{
m_hIn = GetStdHandle(STD_INPUT_HANDLE);
if(m_hIn == INVALID_HANDLE_VALUE || m_hIn == NULL) {
std::cout << "Error occurred obtaining the standard input handle."
<< std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
//-----------------------------------------------------------------------------
// Function/Method: SetErrorHnd()
// Description: Set the standard error handle - Error
// Return: If SetErrorHnd() is successful then EXIT_SUCCESS is
// returned, otherwise EXIT_FAILURE is returned
//-----------------------------------------------------------------------------
// Note: See SetWriteHnd() above for more details
//-----------------------------------------------------------------------------
int vmConsoleApp::SetErrorHnd()
{
m_hError = GetStdHandle(STD_ERROR_HANDLE);
if(m_hError == INVALID_HANDLE_VALUE || m_hError == NULL) {
std::cout << "Error occurred obtaining the standard error handle."
<< std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
//-----------------------------------------------------------------------------
// Function/Method: GetWriteHnd()
// Description: Get the standard output handle - Write
// Return: HANDLE to standard output
//-----------------------------------------------------------------------------
HANDLE vmConsoleApp::GetWriteHnd() const { return m_hOut; }
//-----------------------------------------------------------------------------
// Function/Method: GetReadHnd()
// Description: Get the standard input handle - Read
// Return: HANDLE to standard input
//-----------------------------------------------------------------------------
HANDLE vmConsoleApp::GetReadHnd() const { return m_hIn; }
//-----------------------------------------------------------------------------
// Function/Method: GetErrorHnd()
// Description: Get the standard error handle - Error
// Return: HANDLE to standard error
//-----------------------------------------------------------------------------
HANDLE vmConsoleApp::GetErrorHnd() const { return m_hError; }
//-----------------------------------------------------------------------------
// Function/Method: CreateConsoleApp()
// Description: Creates a console application
// Return: If CreateConsoleApp() is successful then EXIT_SUCCESS is
// returned, otherwise EXIT_FAILURE is returned
//-----------------------------------------------------------------------------
int vmConsoleApp::CreateConsoleApp()
{
SMALL_RECT sWindowSize = { m_nLeft, m_nTop, m_nRight, m_nBottom };
COORD sBufferSize = { sWindowSize.Right, sWindowSize.Bottom };
// The screen buffer is zero based so it's necessary to subtract 1
sWindowSize.Right = sBufferSize.X - 1;
sWindowSize.Bottom = sBufferSize.Y - 1;
if(SetConsoleWindowInfo(m_hOut, TRUE, &sWindowSize) == 0) {
DWORD err = GetLastError();
CONSOLE_SCREEN_BUFFER_INFO SBInfo;
GetConsoleScreenBufferInfo(m_hOut, &SBInfo);
std::cout << "SetConsoleWindowInfo() Error: " << err << std::endl;
std::cout << "The largest console window size on this system is "
<< SBInfo.dwMaximumWindowSize.X << " X "
<< SBInfo.dwMaximumWindowSize.Y << std::endl;
return EXIT_FAILURE;
}
else {
SetConsoleAppTitle();
SetConsoleScreenBufferSize(m_hOut, sBufferSize);
}
return EXIT_SUCCESS;
}
//-----------------------------------------------------------------------------
// Function/Method: SetConsoleAppTitle()
// Description: Set console title
// Return: If SetConsoleAppTitle() is successful then EXIT_SUCCESS is
// returned, otherwise EXIT_FAILURE is returned
//-----------------------------------------------------------------------------
int vmConsoleApp::SetConsoleAppTitle()
{
if( !SetConsoleTitle(m_pchConsoleAppTitle) ) {
DWORD err = GetLastError();
std::cout << "SetConsoleAppTitle() Error: " << err << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
Code:
//-----------------------------------------------------------------------------
// Project: vmAPI Framework
// Name: Color.h
// Description: Color class definition file
// Author: Gerald Bates
//-----------------------------------------------------------------------------
#ifndef __COLOR_H__
#define __COLOR_H__
#include <windows.h>
namespace vm {
#define BLACK 0
#define WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
#define RED FOREGROUND_RED
#define GREEN FOREGROUND_GREEN
#define BLUE FOREGROUND_BLUE
#define YELLOW FOREGROUND_RED | FOREGROUND_GREEN
#define ORANGE FOREGROUND_RED | FOREGROUND_YELLOW
#define CYAN FOREGROUND_GREEN | FOREGROUND_BLUE
#define MAGENTA FOREGROUND_BLUE | FOREGROUND_RED
#define BLINK 128
class vmColor
{
public:
vmColor(int fg = WHITE, int bg = BLACK);
~vmColor();
void SetColor(int fg, int bg);
int GetForegroundColor() const;
int GetBackgroundColor() const;
private:
int m_nForegroundColor;
int m_nBackgroundColor;
};
} // namespace vm
#endif // __COLOR_H__
Code:
//-----------------------------------------------------------------------------
// Project: vmAPI Framework
// Name: Color.cpp
// Description: Color class implementation file
// Author: Gerald Bates
//-----------------------------------------------------------------------------
#include "color.h"
using namespace vm;
//-----------------------------------------------------------------------------
// Function/Method: vmColor(int fg, int bg)
// Description: Color class constructor
// Return: N/A
//-----------------------------------------------------------------------------
vmColor::vmColor(int fg, int bg) { SetColor(fg, bg); }
//-----------------------------------------------------------------------------
// Function/Method: ~vmColor()
// Description: Color class destructor
// Return: N/A
//-----------------------------------------------------------------------------
vmColor::~vmColor() {}
//-----------------------------------------------------------------------------
// Function/Method: SetColor(int fg, int bg)
// Description: Set the text color and background
// Return: void
//-----------------------------------------------------------------------------
void vmColor::SetColor(int fg, int bg)
{
WORD wColor = ((bg & 0x0F) << 4) + (fg & 0x0F);
SetConsoleTextAttribute(GetWriteHnd(), wColor | FOREGROUND_INTENSITY); << ERROR HERE ??
m_nForegroundColor = fg;
m_nBackgroundColor = bg;
}
//-----------------------------------------------------------------------------
// Function/Method: GetForegroundColor()
// Description: Get the current foreground color
// Return: int - Representing the current foreground color
//-----------------------------------------------------------------------------
int vmColor::GetForegroundColor() const { return m_nForegroundColor; }
//-----------------------------------------------------------------------------
// Function/Method: GetBackgroundColor()
// Description: Get the current background color
// Return: int - Representing the current background color
//-----------------------------------------------------------------------------
int vmColor::GetBackgroundColor() const { return m_nBackgroundColor; }
Re: using composition with scope issue
Since the compiler error is a simple line, all you needed to post is the actual implementation of the function that is giving the problem. The implementation of those other functions are not important and adds clutter to the real problem.
As a matter of fact, You didn't even need to post the example you did post:
Code:
class vmColor
{
void CallSomeFunction();
};
class vmConsoleApp
{
public:
void SomeFunction();
vmColor c;
};
void vmColor::CallSomeFunction()
{
SomeFunction();
}
Is this what the code you posted boils down to?
Regards,
Paul McKenzie
Re: using composition with scope issue
Paul, I am no expert so I thought it was better just to post what I did. In future I will try to replicate issues in a more compact way. I noticed you made vmColor c; public in vmConsoleApp so I tried it and I still got the same error? I am lacking in some basic understanding here! I tried making the classes friends of each other and that does not help either?
Re: using composition with scope issue
The vmColor object may be within the vmConsoleApp class, but that doesn't mean it can get unqualified access to vmConsoleApp methods. You have a few options:
1) Make the methods in vmConsoleApp that it needs to access static.
2) Make vmConsoleApp a singleton.
3) Pass a pointer to the vmConsoleApp (typically "this") into the vmColor object to be used in the relevant call. Be careful if you do this in the vmConsoleApp constructor---you shouldn't try to access the pointer before the constructor exits!
Re: using composition with scope issue
Taking Lindley's option #3 one step further...
Since vmColor is a class that can stand completely on it's own, there's really no reason for it to have any knowledge of the vmConsoleApp object. Therefore, you might want to derive from the vmColor class with something like vmConsoleColor, then add a member reference to the vmConsoleApp class within this new derived class. Oh, and don't forget to change the member within your vmConsoleApp object from vmColor to vmConsoleColor.
Re: using composition with scope issue
Quote:
Originally Posted by
Gerald Bates
Paul, I am no expert so I thought it was better just to post what I did. In future I will try to replicate issues in a more compact way.
Every C++ compiler error can be duplicated with a few lines of code and empty or close to empty dummy classes.
Anytime there is an issue with compilation, it is always wise to create a skeleton program like I did, see what the problem is, and given that small code, figure out a solution. It's better to do that than to have be inundated with member functions, comments, constants, and who knows what else that has nothing to do with the real problem. You will appreciate solving issues this way especially when you get to templated code, where the smaller example, the better.
I know what I posted wasn't supposed to compile -- I posted so that I can get a better understanding of what the error is, and hopefully it illustrates succinctly what the problem is to others helping you.
Regards,
Paul McKenzie