I am not completely sure why this is generating that error:
const class MyString {
public:
MyString() { _len = 0; _str = NULL; }
MyString(const char* in);
MyString(const MyString&);
~MyString();
int set(const char*);
int set(const MyString&);
int setLength(int len) { _len = len; return 0; }
int getLength() { return _len; }
char * getStr() { return _str; }
int getStr(char* out) const;
MyString operator+(const MyString & in);
MyString operator+(const char* in);
MyString operator+(const char in) {const char* temp = ∈ return *this + temp; }
MyString operator=(const MyString & in)
{ this->set(in); return *this; }
MyString operator=(const char* in)
{ if(in) this->set(in); return *this; }
MyString operator=(const char in) {const char* temp = ∈ return *this = temp; }
MyString operator+=(const MyString & in)
{ this->set(*this + in); return *this; }
MyString operator+=(const char* in)
{ if(in) this->set(*this + in); return *this; }
MyString operator+=(const char in) { return (*this + in); }
int operator==(const MyString& in);
int operator!=(const MyString& in);
int operator==(const char* in);
int operator!=(const char* in);
friend ostream& operator<<(ostream& os, const MyString & in)
{ os << in._str; return os; }
protected:
char * _str;
int _len;
};
The error is being generated at the last line. The only code before that definition are 'standard' #includes and using namespace std.
The error message you posted is not complete, but nevermind that.
Long story short: remove the const qualifier at the very top of your class declaration, the one just before the class keyword. You can only add cv-qualifiers (const / volatile) either on variables or methods.
Related
I am trying to do operator overloading
My header is:
class Nyble
{
public:
Nyble();
Nyble(const Nyble& n);
Nyble& operator=(const Nyble& n);
~Nyble();
Nyble operator+(const char a);
Nyble operator-(const char a);
Nyble operator+(Nyble& n1);
Nyble operator+();
unsigned char getData();
private:
// Do not change this data
unsigned char data;
}
Source:
#include "Nyble.h"
unsigned char Nyble::getData()
{
return this->data;
}
Nyble Nyble::operator+(const char val)
{
return Nyble(getData()+val);
}
Nyble Nyble::operator-(const char value)
{
return Nyble(value + getData()) ;
}``
I am getting an error saying no suitable constructor exists to convert int to Nyble. If so, what constructor should I declare? Else what changes should I make to the overloading function?
You need to add a constructor for Nyble(getData() + val); and Nyble(value + getData()) to work:
class Nyble {
public:
explicit Nyble(char d); // add this
// ...
};
Nyble::Nyble(char d) : data(d) {} // and the implementation
Though, I recommend that you instead implement operator+ and operator- as free functions and make operator+= and operator-= member functions.
It could look like this:
class Nyble {
public:
Nyble() = default;
explicit Nyble(unsigned char d);
// implement operator+= and operator-= as member functions
Nyble& operator+=(const Nyble& n1);
Nyble& operator-=(const Nyble& n1);
unsigned char getData() const;
unsigned char& getData();
private:
unsigned char data = 0;
};
// operator+ and operator- as free functions:
Nyble operator+(Nyble lhs, const Nyble& rhs);
Nyble operator-(Nyble lhs, const Nyble& rhs);
Nyble::Nyble(unsigned char d) : data(d) {}
// the implementation of the member operator overloads:
Nyble& Nyble::operator+=(const Nyble& rhs) {
data += rhs.data;
return *this;
}
Nyble& Nyble::operator-=(const Nyble& rhs) {
data -= rhs.data;
return *this;
}
unsigned char Nyble::getData() const { return data; }
unsigned char& Nyble::getData() { return data; }
// now the free functions can use the member functions
// `operator+=` and `operator-=`:
Nyble operator+(Nyble lhs, const Nyble& rhs) {
return lhs += rhs;
}
Nyble operator-(Nyble lhs, const Nyble& rhs) {
return lhs += rhs;
}
I'm writing my own typesafe enum header-only library at https://bitbucket.org/chopsii/typesafe-enums
The idea is to replace the non-type-safe c-style enum like:
enum ItemCategory
{
BLOCK,
WEAPON
};
with something that's properly type safe.
So far, my solution uses a macro that, for an example equivalent to the above enum, looks like this:
TypesafeEnum(ItemCategory,
(BLOCK)
(WEAPON)
);
And expands to something that looks like this:
template<typename InnerType>
class Wrapped {
public:
InnerType getValue() const { return _val; }
bool operator<(const Wrapped<InnerType>& rhs) const { ; return _val < rhs._val; }
bool operator>(const Wrapped<InnerType>& rhs) const { ; return _val > rhs._val; }
bool operator==(const Wrapped<InnerType>& rhs) const { ; return _val == rhs._val; }
private:
InnerType _val;
protected:
explicit Wrapped<InnerType>(const InnerType& val) : _val(val) {}
void setValue(const InnerType& val) { _val = val; }
};
class WrappedTypeItemCategory : private Wrapped<int>
{
private:
typedef const std::string* strptr;
typedef const std::string* const cstrptr;
explicit WrappedTypeItemCategory(const std::string& label, int val): Wrapped<int>(val), str(&label)
{}
cstrptr str;
public:
static WrappedTypeItemCategory make(const std::string& label, int val)
{
return WrappedTypeItemCategory(label, val);
}
void operator=(const WrappedTypeItemCategory& rhs)
{
;
setValue(rhs.getValue());
const_cast<strptr>(str) = rhs.str;
}
int getValue() const
{
return Wrapped<int>::getValue();
}
const std::string& getString() const
{
return *str;
}
bool operator<(const WrappedTypeItemCategory & rhs) const
{
;
return getValue() < rhs.getValue();
}
bool operator>(const WrappedTypeItemCategory & rhs) const
{
;
return getValue() > rhs.getValue();
}
bool operator==(const WrappedTypeItemCategory & rhs) const
{
;
return getValue() == rhs.getValue();
}
friend std::ostream & operator<<(std::ostream &os, const WrappedTypeItemCategory& rhs)
{
;
return os << *rhs.str << "(" << rhs.getValue() << ")";
}
};
;
namespace {
template<typename T> class ItemCategoryInner : public TypesafeEnumBase
{
public:
static const WrappedTypeItemCategory BLOCK;
static const WrappedTypeItemCategory WEAPON;
static const std::string BLOCKStr;
static const std::string WEAPONStr;
};
template<typename T> const WrappedTypeItemCategory ItemCategoryInner<T>::BLOCK = WrappedTypeItemCategory::make(ItemCategoryInner<T>::BLOCKStr, 0);
template<typename T> const WrappedTypeItemCategory ItemCategoryInner<T>::WEAPON = WrappedTypeItemCategory::make(ItemCategoryInner<T>::WEAPONStr, 1);
template<typename T> const std::string ItemCategoryInner<T>::BLOCKStr("ItemCategory::BLOCK");
template<typename T> const std::string ItemCategoryInner<T>::WEAPONStr("ItemCategory::WEAPON");
struct ItemCategoryTemplateConstantTrick
{};
};
class ItemCategory : public ItemCategoryInner<ItemCategoryTemplateConstantTrick>
{
private:
const WrappedTypeItemCategory* const val;
public:
class InvalidValueError : public std::runtime_error
{
public:
const int val;
InvalidValueError(int val): std::runtime_error(std::string("Invalid value given for ") + "ItemCategory::make"), val(val)
{}
};
ItemCategory(const WrappedTypeItemCategory& value): val(&value)
{}
void operator=(const ItemCategory& rhs)
{
const_cast<const WrappedTypeItemCategory*>(val) = rhs.val;
}
static ItemCategory make(const int& val)
{
if (val == ItemCategory::BLOCK.getValue()) return ItemCategory(ItemCategory::BLOCK);
if (val == ItemCategory::WEAPON.getValue()) return ItemCategory(ItemCategory::WEAPON);
;
throw InvalidValueError(val);
}
const WrappedTypeItemCategory* const getWrappedValue() const
{
return val;
}
int getValue() const
{
return val->getValue();
}
const std::string & getString() const
{
return val->getString();
}
bool operator<(const ItemCategory& rhs) const
{
return *val < *rhs.val;
}
bool operator>(const ItemCategory& rhs) const
{
return *val > *rhs.val;
}
bool operator==(const WrappedTypeItemCategory& rhs) const
{
return *val == rhs;
}
bool operator!=(const WrappedTypeItemCategory& rhs) const
{
return !(*val == rhs);
}
bool operator<=(const WrappedTypeItemCategory& rhs) const
{
return (*val == rhs || *val < rhs);
}
bool operator>=(const WrappedTypeItemCategory& rhs) const
{
return (*val == rhs || *val > rhs);
}
void print(std::ostream& os) const override
{
os << *val;
}
friend std::ostream & operator<<(std::ostream &os, const ItemCategory& rhs)
{
rhs.print(os);
return os;
}
};
;
If I manually pre-expand it, like I have done here - by pre-compiling to file - then intellisense handles it all up until the line that says:
class ItemCategory : public ItemCategoryInner<ItemCategoryTemplateConstantTrick>
At which point it starts thinking ItemCategoryInner and ItemCategoryTemplateConstantTrick are ambiguous, along with many other things on every few lines of the file.
The header that contains this code is included in many places. I know I'm violating the One Definition Rule, which is why I'm using the Template Constant Trick, but I think I need to violate the ODR as my goal is to have an easy to use Macro based typesafe replacement for C++ enums.
I'm not sure if it's the violation of ODR that is the cause of my issues, or something else. I tried __declspec(selectany) but it didn't seem to help - and I would prefer if this macro would be eventually cross-platform, because if it works out, I have other projects I would use it in.
Either way, the .cpp files etc that make use of the enum are able to, and intellisense correctly suggests the options.
However, on a possibly related note, if I don't pre-expand the macro, intellisense isn't able to parse it and it doesn't know what a ItemCategory is at all, even though it compiles and works fine.
I just want my intellisense to work properly with my typesafe enums - it slows down intellisense and confuses it in other code in the same project.
When it gets to the delete portion where test2 needs to delete the String object it crashes. I am not sure why it crashes. It says "Debug Assertion failed!". Am I deleting the dynamically alloacted char array wrong?
strdrv.cpp:
#include <iostream>
#include <stdlib.h>
#include "strdrv.h"
int main() {
test2();
return 0;
}
void test2() {
cout << "2. Testing S2: String one arg (char *) constructor."
<< endl << endl;
csis << "2. Testing S2: String one arg (char *) constructor."
<< endl << endl;
String s2("ABC");
s2.print();
wait();
}
String.cpp:
#include "String.h"
#include <iostream>
using namespace std;
String::String(char* s) {
int sLength = 0;
for (int i = 0; s[i] != '\0'; i++) {
sLength++;
}
buf = new char[sLength+1];
dynamicallyAlloc = true;
buf = s;
length = sLength;
/*buf[length] = '\0';*/
}
String::~String() {
if(dynamicallyAlloc)
delete []buf;
}
String.h:
#ifndef _STRING_H
#define _STRING_H
#include <iostream>
using namespace std;
class String {
protected:
bool dynamicallyAlloc;
char nullChar;
int length;
char* buf;
void calculateStringLength();
public:
String();
String(char*);
String(char);
String(int);
String(const String&);
String(char, int);
~String();
int getLength() const;
char* getString() const;
String& operator=(const String&);
String& operator=(const char*);
String& operator+=(const String&);
String operator+() const;
char& operator[](int);
String& operator++();
String& operator--();
String operator++(int);
String operator--(int);
String substr(int, int);
void print();
friend String operator+(const String&, const String&);
friend String operator+(const String&, const char*);
friend String operator+(const char*, const String&);
friend String operator+(const String&, char);
friend String operator+(char, const String&);
friend char* operator+(const String&, int);
friend char* operator+(int, const String&);
friend int operator==(const String&, const String&);
friend int operator!=(const String&, const String&);
friend int operator<(const String&, const String&);
friend int operator<=(const String&, const String&);
friend int operator>(const String&, const String&);
friend int operator>=(const String&, const String&);
friend ostream& operator<<(ostream& os, const String& s1);
};
#endif
To copy the array contents, do not copy the pointer, Instead of
buf = s;
you want copy the contents
memcpy(buf,s, sLength+1);
This preserves the buf you have allocated for later deletion.
This is supposed to be a string class with a bunch of operators and functions, including two friend functions. And those two cause some trouble for me, because the compiler says that they can not access the private members. Here is my string.h:
#include <iostream>
#ifndef STR_H
#define STR_H
namespace MyStr
{
class Str
{
private:
unsigned int length;
char *data;
public:
Str();
Str(const Str&);
Str(const char*);
Str(char c, unsigned int db);
~Str();
char* cStr() const;
unsigned int getLength() const;
lots of irrevelant functions here...
friend int operator/ (const Str&, char);
friend std::ostream& operator<< (std::ostream&, const Str&);
};
}
#endif /* STR_H */
here is the main.cpp:
#include <iostream>
#include "Str.h"
using namespace std;
using namespace MyStr;
ostream& operator<< (ostream& out,const Str& str)
{
for (int i=0; i<str.length; i++)
{
out<<str.data[i];
}
out<<endl;
return out;
}
int operator/ (const Str& str, char c)
{
for (int i=0; i<str.length; i++)
{
if(str.data[i]==c) return i;
}
return -1;
}
This code won't compile, the compiler claiming that the Str members are private.
You should pay more attention to namespaces.
class Str {
private:
unsigned int length;
char *data;
public:
Str(){}
Str(const Str&){}
Str(const char*){}
Str(char c, unsigned int db){}
// maybe something more...
friend int operator/ (const Str&, char);
friend std::ostream& operator<< (std::ostream&, const Str&);
};
ostream& operator<< (ostream& out,const Str& str)
{
for (int i=0; i<str.length; i++)
out<<str.data[i];
out<<endl;
return out;
}
int operator/ (const Str& str, char c)
{
for (int i=0; i<str.length; i++)
if(str.data[i]==c) return i;
return -1;
}
int main()
{
Str s;
cout<<s;
return 0;
}
You get error because of the unmatched namespaces. If you prefer to stick with MyStr then you should add namespace MyStr to overloaded friend operators. This is how you can do it: (operators should be defined within namespace MyStr)
namespace MyStr {
ostream& operator<< (ostream& out,const Str& str)
{
for (int i=0; i<str.length; i++)
{
out<<str.data[i];
}
out<<endl;
return out;
}
int operator/ (const Str& str, char c)
{
for (int i=0; i<str.length; i++)
{
if(str.data[i]==c) return i;
}
return -1;
}
}
When you declare the friend functions inside Str they are considered to be in the immediately enclosing namespace, MyStr.
The operators you define are in the global namespace, so the compiler believes that those are two entirely different operators, and not the friends.
You can solve this by adding
namespace MyStr
{
}
around the operators in the .cpp file.
I am modifying code that was given to me to allow the throwing of exceptions. The problem is that the declarations don't seem to be accepting Error, the exception type as a valid class.
The code is below:
// Interface for a simple String class to encapsulate a C character string
#ifndef _MYSTRING_H_
#define _MYSTRING_H_
#include <string.h>
#include <iostream>
#include <stdexcept>
using namespace std;
class MyString {
public:
// Constructors and destructor
MyString(const char * = ""); // Create from C string
MyString(const MyString &); // Copy constructor
~MyString() { delete [] sdata; }
// Assignment
MyString & operator = (const MyString &);
MyString & operator = (const char *);
MyString & operator += (const MyString &);
MyString & operator += (const char &);
// Character access
char & operator [] (int i) throw(MyString::Error);
char operator [] (int i) const throw(MyString::Error){
return (i < 0 || i >= len) ? '\0' : sdata[i];
}
// Substrings
MyString operator () (unsigned int start, unsigned int count) const throw(MyString::Error);
// Concatenation
MyString operator + (const MyString &) const;
MyString operator + (const char &) const;
// Cast to c string
operator const char * () const { return sdata; }
// Query methods
unsigned int length() const { return len; }
class Error: public exception{
public:
//ERROR CODES
static const int SUBSTRING_ERR = 0;
static const int INDEX_ERR = 1;
static const int ALLOC_ERR = 2;
int errorCode;
int leftIndex;
int count;
int size;
Error(int errCode){ //Alloc error
errorCode = errCode;
}
Error(int errCode, int left, int len){ //Index error
errorCode = errCode;
leftIndex = left;
size = len;
}
Error(int errCode, int left,int substrCount, int len){ //Substring error
errorCode = errCode;
leftIndex = left;
size = len;
count = substrCount;
}
};
private:
char * sdata; // Storage for the characters
unsigned int len; // Current length
// Private constructor for pre-allocation
MyString(const char *, unsigned int);
};
inline ostream & operator << (ostream & o, const MyString & s) {
return o << (const char *) s;
}
inline bool operator == (const MyString & lhs, const MyString & rhs) {
return (::strcmp(lhs, rhs) == 0) ? true : false;
}
inline bool operator != (const MyString & lhs, const MyString & rhs) {
return (lhs == rhs) ? false : true;
}
inline bool operator < (const MyString & lhs, const MyString & rhs) {
return (::strcmp(lhs, rhs) < 0) ? true : false;
}
inline bool operator >= (const MyString & lhs, const MyString & rhs) {
return (lhs < rhs) ? false : true;
}
inline bool operator > (const MyString & lhs, const MyString & rhs) {
return (::strcmp(lhs, rhs) > 0) ? true : false;
}
inline bool operator <= (const MyString & lhs, const MyString & rhs) {
return (lhs > rhs) ? false : true;
}
inline ostream & operator << (ostream & o, const MyString::Error & s) {
return o << "NOM"; //TODO
}
#endif
Here is the full error message:
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:26: error: expected type-specifier
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:26: error: expected )'
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:26: error: expected ‘;’
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:27: error: expected type-specifier
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:27: error: expected)'
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:27: error: expected ‘;’
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:32: error: expected ;' before ‘MyString’
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:32: error: expected type-specifier
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:32: error: expected)'
/Users/alexanderstein/Documents/School/2011-2012/Term 3/CIS 330/6/Mystring.h:32: error: expected ‘;’
You need to declare the MyString::Error class before it is used:
class MyString {
public:
// constructors, assignment operators, increment operators as before
class Error: public std::exception{ ... }
// Character access and methods using MyString::Error
char & operator [] (int i) throw(MyString::Error);
char operator [] (int i) const throw(MyString::Error){ ... }
};
I would strongly advise against using namespace std and any other namespace in header files. Also, exception specifications are discouraged and deprecated in C++11.
I believe it's operator[] - single token, not operator [] - two tokens. Ditto everywhere else.