I’ve been told to convert a standard C++ program into an object-oriented one, using the principals of polymorphism, encapsulation and inheritance.
I would appreciate any help

// Purpose
// A program to demonstrate the application of a simple digital filter
// 
// Overview
// A sequence of data items and digital filter values need to be entered by the
// user. The application of the filter to the data involves a simple convolution 
// operation. The filtered data are stored separately. 

// The program checks the following
// 1. The data and filter values must have been entered before the filter is 
//    applied
// 2. The filter is not applied if the number of filter values is greater than
//    the number of input data values
// 3. The data and filter values must have been entered and the filter applied 
//    before the filtered data can be displayed
#include <iostream>
using namespace std;

// the data values and the filter
struct TheFilter {
  double* Values;   // the filter values
  unsigned long Length;  // number of filter values
  bool Valid;   // true if the filter values have been Valid by the user
};

struct TheData {
  double* Values;  // holds the data to be filtered
  unsigned long Length;  // number of data values
  bool Valid;   // true if the data values have been Valid by the user
};

// function return values
enum {OK,FILTER_TOO_LONG};

// function prototypes
void EnterData(TheData&);
void EnterFilter(TheFilter&);
int ApplyFilter(TheFilter, TheData, TheData&);
void DisplayData(TheFilter, TheData, TheData);

// Control the principal operations of the program
// Arguments: None
// Returns: 0 on completion
int main()
{
  // define the filter and its initial values
  TheFilter Filter = {0,0,false};

  // define the original data and its initial values
  TheData OriginalData = {0,0,false};

  // define the filtered data and its initial values
  TheData FilteredData = {0,0,false};

  char UserInput;

  // loop until the user wishes to exit
  while (1) {

    // show the menu of options
    cout << endl;
    cout << "Filter Menu" << endl;
    cout << "-----------" << endl;
    cout << "1. Enter data for filtering" << endl;
    cout << "2. Enter filter values" << endl;
    cout << "3. Apply filter" << endl;
    cout << "4. Display filtered data" << endl;
    cout << "5. Exit from the program" << endl << endl;

    // get the user's choice
    cout << "Enter your option: ";
    cin >> UserInput;
    cout << endl;

    // act on the user's input
    switch(UserInput) {
      case '1':
        EnterData(OriginalData);
        FilteredData.Valid = false;
        break;

      case '2':
        EnterFilter(Filter);
        FilteredData.Valid = false;
        break;      

      case '3':
        if (Filter.Valid == true && OriginalData.Valid == true &&
            FilteredData.Valid == false) {
          if (ApplyFilter(Filter,OriginalData,FilteredData) == FILTER_TOO_LONG) {
             cout << "The filter must not be longer than the data" << endl;
          }
          else {
            FilteredData.Valid = true;
            cout << "Filter applied" << endl;
          }
        }
        break;

      case '4':
        if (Filter.Valid == true && OriginalData.Valid == true &&
            FilteredData.Valid == true) {
          DisplayData(Filter,OriginalData,FilteredData);
        }
     else {
        cout << "Data have not yet been filtered" << endl;
     }
        break;

      case '5':
        delete [] Filter.Values;
        delete [] OriginalData.Values;
        delete [] FilteredData.Values;
        return 0;
        break;

      default:
        cout << "Invalid entry" << endl << endl;
        break;
    }
  }
}

// Allow the user to enter the data to be filtered
// Arguments:
//   (1) the structure containing the input data
// Returns: nothing
// 
void EnterData(TheData& GetData)
{  
  // initialize the data structure that holds the data to be filtered, including getting
  // the number of data values from the user
  delete [] GetData.Values;
  cout << "How many data values do you wish to enter: ";
  cin >> GetData.Length;
  GetData.Valid = true;

  // allocate memory to the data
  GetData.Values = new double[GetData.Length];
  if (GetData.Values == 0) {
    cout << "Unable to allocate sufficient memory" << endl;
    exit(1);
  }

  // obtain all of the data values
  cout << endl;
  cout << "Enter the data values" << endl;
  cout << "---------------------" << endl;
  for (unsigned long CountData = 0; CountData < GetData.Length; CountData++) {
    cout << "Enter value " << CountData+1 << ": ";
    cin >> GetData.Values[CountData];
  }
}

// Allow the user to enter the filter values
// Arguments:
//   (1) the structure of the filter to be defined
// Returns: nothing
// 
void EnterFilter(TheFilter& GetFilter)
{  
  // initialize the data structure that holds the filter, including getting the number of
  // filter values from the user
  delete [] GetFilter.Values;
  cout << "How many data values do you wish to enter: ";
  cin >> GetFilter.Length;
  GetFilter.Valid = true;

  // allocate memory to the filter values
  GetFilter.Values = new double[GetFilter.Length];
  if (GetFilter.Values == 0) {
    cout << "Unable to allocate sufficient memory" << endl;
    exit(1);
  }

  // obtain all of the filter values
  cout << endl;
  cout << "Enter the filter values" << endl;
  cout << "-----------------------" << endl;
  for (unsigned long CountData = 0; CountData < GetFilter.Length; CountData++) {
    cout << "Enter value " << CountData+1 << ": ";
    cin >> GetFilter.Values[CountData];
  }
}

// Apply the filter to the input data and store in the filtered data structure
// Arguments:
//   (1) the structure of the filter to be applied
//   (2) the structure containing the data to be filtered
//   (3) the structure to hold the filtered data
// Returns: OK - if the filter is applied
//          FILTER_TOO_LONG - the filter is longer than the data 
//  
int ApplyFilter(TheFilter Filter, TheData DataIn, TheData& DataOut)
{  
  // return an error if the filter is longer than the data
  if (Filter.Length > DataIn.Length) return FILTER_TOO_LONG;

  // initialize the data structure that holds the filtered data
  delete [] DataOut.Values;
  DataOut.Length = DataIn.Length - Filter.Length + 1;

  // get memory for the filtered data
  DataOut.Values = new double[DataOut.Length];
  if (DataOut.Values == 0) {
    cout << "Unable to allocate sufficient memory" << endl;
    exit(1);
  }

  // apply the filter to the data
  for (unsigned long CountData = 0; CountData < DataOut.Length; CountData++) {
    DataOut.Values[CountData] = 0.0; 
    for (unsigned long CountFilter = 0; CountFilter<Filter.Length; CountFilter++) {
      DataOut.Values[CountData] += DataIn.Values[CountData+CountFilter] *
                                   Filter.Values[CountFilter]; 
    }
  }

  return OK;
}


// Display input data, filter values and output data
// Arguments:
//   (1) the structure of the filter to be applied
//   (2) the structure containing the data to be filtered
//   (3) the structure that holds the filtered data
// Returns: nothing
// 
void DisplayData(TheFilter Filter, TheData DataIn, TheData DataOut)
{  
  // display all of the input data values
  cout << endl;
  cout << "The input data values" << endl;
  cout << "---------------------" << endl;
  cout << "[ ";
  for (unsigned long CountData = 0; CountData < DataIn.Length; CountData++) {
    cout << DataIn.Values[CountData] << " ";
  }
  cout << "]" << endl;

  // display all of the filter values
  cout << endl;
  cout << "The filter values" << endl;
  cout << "-----------------" << endl;
  cout << "[ ";
  for (unsigned long CountData = 0; CountData < Filter.Length; CountData++) {
    cout << Filter.Values[CountData] << " ";
  }
  cout << "]" << endl;

  // display all of the data output values
  cout << endl;
  cout << "The data output values" << endl;
  cout << "----------------------" << endl;
  cout << "[ ";
  for (unsigned long CountData = 0; CountData < DataOut.Length; CountData++) {
    cout << DataOut.Values[CountData] << " ";
  }
  cout << "]" << endl;
}

Hiya ,.

I dont think polymorphism is neccessary here. I would simply convert the filter and data to classes. A class is the same as a struct in c++ (apart from different default permissions ie in a struct all members are public by default, where as in a class they are all private by default)

All you have to do is combine the data and the functions for each object into a single entity.

So take our filter for example . you take your current struct and add to it member functions. these are functions which operate upon the data within the instance of the stuct or class from which they were called.

if you had a class with 2 instances like this

class AddFive
{
public: 
   int x;
   int Add5(void) { return x+5; };
};

// instances of this
AddFive inst1, inst2;

//set thier values 
inst1.x = 5;
inst2.x = 3;

//run the functions
int y = inst1.Add5;
int z = inst2.Add5;

Then y would hold 10 and z holds 8. Hope that explains how member functions work. So basically your looking to do the same with your filter. add the functions to do the filters work to the struct or class and then you can use the same methods but without needing references to the filter.

The ways in which you could do it are many using OOP but thats what they are looking for you to try and do. the sky is the limit

Although this approach only utilises OOP for encapsulation. im my opinion the data and filters are unrelated so are not suitable for inheritance or polymorphism.

Im sorry if this is information that you know but if you give a more specific question(s) ill do what i can to help ya some more

Thank you very much for attempting but i could show you my attempt so far which has errors and maybe that could help me more. would apreciate any suggestions or corrections. the code

#include <iostream>
using namespace std;

// ------CLASS DEFINITIONS------

class TheData 
{
public:								
	TheData(double* = 0, unsigned long = 0, bool = false);			
	~TheData();						

	void SetValue(double*, TheData&);
	void SetValue(unsigned long, TheData&);
	void SetValue(bool, TheData&);

	double* ShowValue_Values();
	unsigned long ShowValue_Length(); 
	bool ShowValue_Valid();

	void EnterData(TheData& OriginalData);				
	void DisplayData(TheData OriginalData, TheData FilteredData) const;	
private:							
	double* Values;						
	unsigned long Length;						
	bool Valid;							
};

class TheFilter
{
public:
	TheFilter(double* = 0, unsigned long = 0, bool = false);		
	~TheFilter();						
	
	void EnterFilter(TheFilter& Filter);					

	void SetValue(double*, TheFilter&);
	void SetValue(unsigned long, TheFilter&);
	void SetValue(bool, TheFilter&);

	double* ShowValue_Values();
	unsigned long ShowValue_Length(); 
	bool ShowValue_Valid();

	int ApplyFilter(TheData OriginalData, TheFilter Filter, TheData& FilteredData);
	void DisplayData(TheFilter Filter) const;				
private:								
	double* Values;						
	unsigned long Length;						
	bool Valid;							
};

/*class PrivateData : public TheData, public TheFilter
{
public:
	double* Values;																
	unsigned long Length;														
	bool Valid;	
};*/

enum {OK,FILTER_TOO_LONG};		// Function return values

// ------------MAIN------------

int main()
{
	// main() to create the first object only!
	TheData OriginalData;						TheData FilteredData;							TheFilter Filter;											
	OriginalData.EnterData;						OriginalData.DisplayData;											
	char UserInput;

	// loop until the user wishes to exit
	while (1) {
	    
		// show the menu of options
		cout << endl;
		cout << "Filter Menu" << endl;
		cout << "-----------" << endl;
		cout << "1. Enter data for filtering" << endl;
		cout << "2. Enter filter values" << endl;
		cout << "3. Apply filter" << endl;
		cout << "4. Display filtered data" << endl;
		cout << "5. Exit from the program" << endl << endl;
	    
		// get the user's choice
		cout << "Enter your option: ";
		cin >> UserInput;
		cout << endl;
	    
		// act on the user's input
		switch(UserInput) {
		case '1':
			OriginalData.EnterData(OriginalData);
			FilteredData.SetValue(false, OriginalData);		
			break;

		case '2':
			Filter.EnterFilter(Filter);
			FilteredData.SetValue(false, FilteredData);
			break;      
	 
		case '3':
			if (Filter.ShowValue_Valid() == true && OriginalData.ShowValue_Valid() == true && FilteredData.ShowValue_Valid() == false) 
			{
				if (Filter.ApplyFilter(OriginalData, Filter, FilteredData) == FILTER_TOO_LONG) 
				{
					cout << "The filter must not be longer than the data." << endl;
				}
				else 
				{
					FilteredData.SetValue(true, FilteredData);
					cout << "Filter applied." << endl;
				}
			}
			break;

		case '4':
			if (Filter.ShowValue_Valid() == true && OriginalData.ShowValue_Valid() == true && FilteredData.ShowValue_Valid() == true) 
			{
				OriginalData.DisplayData(OriginalData, FilteredData);
				Filter.DisplayData(Filter);
			}
			else 
			{
				cout << "Data have not yet been filtered" << endl;
			}
			break;

		case '5':
		/*delete [] Filter.Values;
			delete [] OriginalData.Values; UNSURE WHAT TO DO HERE!
			delete [] FilteredData.Values;*/					return 0;
			break;

		default:
			cout << "Invalid entry" << endl << endl;
			break;
		}
	}
}

// --THEDATA MEMBER FUNCTIONS--

TheData::TheData(double*, unsigned long, bool)
{
	Values = 0;
	Length = 0;		
	Valid = false;						
}

TheData::~TheData()																// TheData destructor function
{
	/*delete[] OriginalData.Values;					
	delete[] OriginalData.Length;
	delete[] OriginalData.Valid;
																					// Free memory
	delete[] FilteredData.Values;
	delete[] FilteredData.Length;
	delete[] FilteredData.Valid;*/
}

void TheData::EnterData(TheData& OriginalData)
{
	// initialize the data structure that holds the data to be filtered, including getting
	// the number of data values from the user
	delete[] OriginalData.Values;
	cout << "How many data values do you wish to enter: ";
	cin >> OriginalData.Length;
	OriginalData.Valid = true;

	// allocate memory to the data
	OriginalData.Values = new double[OriginalData.Length];
	
	if (OriginalData.Values == 0) 
	{
		cout << "Unable to allocate sufficient memory." << endl;
		exit(1);
	}

	// obtain all of the data values
	cout << endl;
	cout << "Enter the data values" << endl;
	cout << "---------------------" << endl;
	
	for (unsigned long CountData = 0; CountData < OriginalData.Length; CountData++) 
	{
		cout << "Enter value " << CountData + 1 << ": ";
		cin >> OriginalData.Values[CountData];
	}
}

void TheData::DisplayData(TheData OriginalData, TheData FilteredData) const
{
	// display all of the input data values
	cout << endl;
	cout << "The input data values" << endl;
	cout << "---------------------" << endl;
	cout << "[ ";
	
	for (unsigned long CountData = 0; CountData < *OriginalData.Values; CountData++) 
	{
		//cout << OriginalData.SetValue(OriginalData.Values[CountData], OriginalData) << " ";
	}
	
	cout << "]" << endl;
	
	// display all of the data output values
	cout << endl;
	cout << "The data output values" << endl;
	cout << "----------------------" << endl;
	cout << "[ ";

	for (unsigned long CountData = 0; CountData < FilteredData.Length; CountData++) 
	{
		//cout << FilteredData.SetValue(FilteredData.Values[CountData], FilteredData) << " ";
	}
	cout << "]" << endl;
}

void TheData::SetValue(double* SetValue, TheData& Original_or_Filtered_Data)
{
	Original_or_Filtered_Data.Values = SetValue;
}

void TheData::SetValue(unsigned long SetValue, TheData& Original_or_Filtered_Data)
{
	Original_or_Filtered_Data.Length = SetValue;
}

void TheData::SetValue(bool SetValue, TheData& Original_or_Filtered_Data)
{
	Original_or_Filtered_Data.Valid = SetValue;
}

double* TheData::ShowValue_Values()
{
return 0;
}

unsigned long TheData::ShowValue_Length()
{
return 0;
}

bool TheData::ShowValue_Valid()
{
return false;
}

// -THEFILTER MEMBER FUNCTIONS-

TheFilter::TheFilter(double*, unsigned long, bool)			
{
	Values = 0;		
	Length = 0;				
	Valid = false;	
}

TheFilter::~TheFilter()		
{
	// delete[] "something"?														// Free memory
}

void TheFilter::EnterFilter(TheFilter& Filter)
{
	// initialize the data structure that holds the filter, including getting the number of
	// filter values from the user
	delete [] Filter.Values;
	cout << "How many data values do you wish to enter: ";
	cin >> Filter.Length;
	Filter.Valid = true;

	// allocate memory to the filter values
	Filter.Values = new double[Filter.Length];

	if (Filter.Values == 0) 
	{
		cout << "Unable to allocate sufficient memory" << endl;
		exit(1);
	}

	// obtain all of the filter values
	cout << endl;
	cout << "Enter the filter values" << endl;
	cout << "-----------------------" << endl;

	for (unsigned long CountData = 0; CountData < Filter.Length; CountData++) 
	{
		cout << "Enter value " << CountData + 1 << ": ";
		cin >> Filter.Values[CountData];
	}
}

int TheFilter::ApplyFilter(TheData OriginalData, TheFilter Filter, TheData& FilteredData)
{
	// return an error if the filter is longer than the data
	if (Filter.Length > OriginalData.Length) return FILTER_TOO_LONG;
	
	// initialize the data structure that holds the filtered data
	delete[] FilteredData.Values;
	FilteredData.Length = OriginalData.Length - Filter.Length + 1;
	
	// get memory for the filtered data
	FilteredData.Values = new double[FilteredData.Length];
	
	if (FilteredData.Values == 0) 
	{
		cout << "Unable to allocate sufficient memory" << endl;
		exit(1);
	}

	// apply the filter to the data
	for (unsigned long CountData = 0; CountData < FilteredData.Length; CountData++) 
	{
		FilteredData.Values[CountData] = 0.0;
		
		for (unsigned long CountFilter = 0; CountFilter < Filter.Length; CountFilter++) 
		{
			FilteredData.Values[CountData] += OriginalData.Values[CountData + CountFilter] * Filter.Values[CountFilter];
		}
	}
	return OK;
} 

void TheFilter::DisplayData(TheFilter Filter) const
{
	// display all of the filter values
	cout << endl;
	cout << "The filter values" << endl;
	cout << "-----------------" << endl;
	cout << "[ ";
	
	for (unsigned long CountData = 0; CountData < Filter.Length; CountData++) 
	{
		//cout << Filter.SetValue(Filter.Values[CountData], Filter) << " ";
	}
	
	cout << "]" << endl;
}

void TheFilter::SetValue(double* SetValue, TheFilter& Filter)
{
	Filter.Values = SetValue;
	//cout << "Testing Values: " << Filter.Values << " = " << SetValue;	
}

void TheFilter::SetValue(unsigned long SetValue, TheFilter& Filter)
{
	Filter.Length = SetValue;
	//cout << "Testing Length: " << Filter.Length << " = " << SetValue;	
}

void TheFilter::SetValue(bool SetValue, TheFilter& Filter)
{
	Filter.Valid = SetValue;
	//cout << "Testing Valid: " << Filter.Valid << " = " << SetValue;	
}

double* TheFilter::ShowValue_Values()
{
	double* ShowValue;
	ShowValue = 0; //Filter.Values;	

	return ShowValue;
}

unsigned long TheFilter::ShowValue_Length()
{
	unsigned long ShowValue;
	ShowValue = 0; //Filter.Length;

	return ShowValue;
}

bool TheFilter::ShowValue_Valid()
{
	bool ShowValue;
	ShowValue = false; //Filter.Valid;

	return ShowValue;
}

okie dokie taking the first class as an attempt ill put here what i would use and it should help a bit

class TheData
{
public:
   //TheData(double* = 0, unsigned long = 0, bool = false);
   TheData(void) : m_length(0), m_valid (false) {} ; //initilisers are the way to go here (not sure about comma seperation sorry but i think its commas)

   ~TheData() { m_values.clear() }; //empty the values array

   //void SetValue(double*, TheData&);
   void AddValue(double value) { m_values.push_back(value); }

   //void SetValue(unsigned long, TheData&);
   void SetLength(unsigned int length) 
   {
     //do range checking if neccessary
     m_length = length;
   }
   //void SetValue(bool, TheData&);
   void setValid(bool valid) { m_valid = valid; }

   //double* ShowValue_Values();
   ostream printValue_values(ostream& writeTo)
   {
     for ( std::vector<double>::const_iterator n = m_values.begin();
           n != m_values.end(); n++ )
     {
        writeTo<<n; //this loops through all the values and writes them to a stream

        // the bits around this fn mean u can do cout<<inst.printValueValues()<<"end of values"<<endl;
        /* and also while(inst.printValue_values())
                    {
                       //do something i dunno
                    }
         */ 
     }
   }  
 
  //additionally if you need raw data
  std::vector<double> getValue_values(void) {return m_values };

  //unsigned long ShowValue_Length();
  unsigned int getValue_length(void) { return m_length; }

   //bool ShowValue_Valid();
   bool getValue_valid(void) {return m_valid};
 
   //not sure what u wanna do here? ill assume its input form the keyboard
   //in that case use the setValue function above which appends values one at a time
   //void EnterData(TheData& OriginalData);
   

   //void DisplayData(TheData OriginalData, TheData FilteredData) const;
   //have each data instance display only its own data thats the idea of OOP
   //ostream displayData (ostream& writeTo)
   {
     //display whatever start text you want
     writeTo<<"Displaying data: "<<endl;
     writeTo<<"Values:"<<printValue_values()<<endl; //you got a function to do that bit use it :)
     writeTo<<"Length: "<<m_length<<endl; //for single values however its not worth it
     //you get the idea here ,..
   }
private:
std::vector<double> m_values; //look into vectors they are your friend
unsigned long m_length;
bool m_valid;
};

Try that on for size and see if you understand how it works for a bit ,...if concepts are a bit strange remember google is your friend.

Hope this helps you

EDIT!: psst! i typed all that code so its very likely it has errors please only use it as reference and write the code to do what im trying to show here properly as i may have some syntax issues and the likes .

Hi. thanks again for taking time to help me out I will try my best to understand the code you wrote to me. at this moment I do not really understand if you mean the code I wrote is wrong or you are suggesting a better/easier way of doing it. So therefore here is the scope that I had to follow when writing my code (I am sorry for not sending it earlier).
Another thing is I think ApplyFilter() is supposed to be a member function of either TheData or TheFilter but I am not sure how I can do this.For the time being, I've made ApplyFilter() a member function of the TheData class , accessing TheFilter's private members through the ShowValue and SetValue member functions. But i really need some external input on this part of the code. I'd much rather obtain the highest possible marks than build the best possible program.


Before writing your code you will need to think carefully about the following (HINT: these are hints!).

1 Decide on the classes you need. You should also be careful to include a set of classes that
implement the functionality of the code in such a way that they could be used by other
developers.

2. To establish suitable member functions, take into account the responsibilities of each class; for
example, which class should perform the filtering operation?

3. Encapsulation dictates that, as far as possible, an object should be responsible for its own data.
4. Use polymorphism only as appropriate. The general rule is that if an inbuilt operator matches
the purpose of a member function then it should be overloaded.

5. Use inheritance only where necessary. Only if you can reasonable say that object A is a type of
object B should A inherit from B. For example, a car is a type of vehicle, but a table isn’t a type
of elephant (even if both have four legs).

The following also forms part of the specification (for both the part B and part C modules).

1. The program must use an object-oriented approach; it must contain only member functions
(other than main() which should do no more than create the first object).

2. All members must be private.

3. Document properly the code you add. Don’t document every line of code - just the major
blocks of code (see the marking scheme).

4. The structure of your code should be neat and easy to follow.

I find the way best to do this as it is a filter is to think in terms of input process output ,...

You have a filter. It requires some settings of its own to define its behaviour ,... It is fed some data, and it outputs new data. This would lead me to the same conclusion you had made about classes. you need a data class and a filter class.

Next, think in terms of the big picture. you want a filter to be able to accept 2 different sets of data one is the configuration data so you will need member functions for inputting that. and the second data that it accepts is your data class. it will need a member function to tell it to process this data which will use the second data class instance to store its result.

so in a simplified terms i think your code is something like this

class dataBlock 
{
public:
  //input function
  void addItem(<type> name);

  //output functions
  int  getNumItems(void);
  <type> getElement(int element);

private:
  /* this is where you store the underlying data structure be it an array or a vector whatever, and a counter of the number of elements in the structure */

};

class filter
{
public:
  /* configuration members */ //im unsure what kind of filter so you will have to decide upon these. 

  /* data processing fn */
  bool applyFilter(dataBlock& input, dataBlock& output); 
  /*return false here if you are unable to compute for whatever reason or use    integer error codes or instead of bool make it a void return and throw exceptions */  
  
}

int main()
{
  filter myFilter;
  dataBlock origData, newData;
 
 //fill in your classes with the information they need here 

 //next process the data 

 if(!filter.applyFilter(origData, newData) )
 {
   //the filtering operation failed ,.... do whatever handling you need
   return -1;
 } 

 //print your results 

 return 0;
}

Thats in a nutshell what i think you want to do to get good marks in this assignment ,... and from that structure you can hopefully fill in the rest. the code i had done for you earlier was a bit of this is an easier way to write it and a few bits of what looked like errors to me but i cant be sure as it may have been what you intended to do .

Hope this helps you get on your way now and makes how to use oop a bit clearer in this simple scenario.

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.