Str greeting = "Hello, " + name + "!";
where "name" is a Str, then I get a compilation error, saying "'operator +': 2 overloads have similar conversions, could be 'Str operator +(const Str &,const Str &)' or 'built-in C++ operator+(const char [8], int)'.#include <iterator>
#include <vector>
#include<iostream>
using namespace std;
class Str
{
private:
std::vector<char> data;
public:
typedef std::vector<char>::size_type size_type;
typedef std::vector<char>::iterator iterator;
typedef std::vector<char>::const_iterator const_iterator;
iterator begin() { return data.begin(); }
const_iterator begin() const { return data.begin(); }
iterator end() { return data.end(); }
const_iterator end() const { return data.end(); }
// default constructor must be defined explicitly, since non-default constructors are also defined
Str() { }
Str(const size_type n, const char c) : data(n, c) { }
Str(const char* cp)
{
std::copy(cp, cp + std::strlen(cp), std::back_inserter(data));
}
// Since this is a template, the iterators can be anything: pointers in an array of chars, std::vector<string> iterators, std::std::vectortor<string> iterators, std::list<string> iterators, etc.
template <class In> Str(In b, In e)
{
std::copy(b, e, std::back_inserter(data));
}
char& operator[](size_type i) { return data[i]; }
const char& operator[](size_type i) const { return data[i]; }
Str& operator+=(const Str& s)
{
std::copy(s.data.begin(), s.data.end(), std::back_inserter(data));
return *this;
}
size_type size() const
{
return data.size();
}
// conversion operators
operator std::vector<char>() const;
operator bool() const;
template <class In> void insert(iterator dest, In b, In e)
{
data.insert(dest, b, e);
}
};
Str operator+(const Str& s1, const Str& s2)
{
Str s = s1;
s += s2;
return s;
}
Str::operator std::vector<char>() const
{
std::vector<char> ret = data;
return ret;
}
Str::operator bool() const
{
if (data.size() > 0)
return true;
return false;
}
int main()
{
Str name = "Joe";
Str greeting = "Hello, " + name + "!";
return 0;
}
str() = default;
class str: private std::vector<char>
{
public:
// bring iterators to visible scope
using std::vector<char>::begin;
using std::vector<char>::end;
// constructor and other class stuffs
str() = default;
str(std::string const&);
str(char);
// ect ...
private:
};
inheriting privatly from std::vector<char>
>>>> Remove this horrible "using namespace std" directive, it has no business in modern C++ code.It is considered a bad practice:
>>Why? It's a matter of personal preference. There is nothing inherently wrong with importing a namespace as long as you understand what it does.
namespace MyNameSpace
{
class string
{
};
}
using namespace std; // ops !
using namespace MyNameSpace; // ops !
int main()
{
string myString; // angry compiler !!
}
>>>> Instead of re-inventing the wheel, what about inheriting privatly from std::vector<char>Private inheritance !!
>>This is bad advice.
With private inheritance, a class is implemented "as a"
#include <iostream>
#include <memory>
class foo
{
public:
~foo()
{
std::cout << "foo destructor" << std::endl;
}
void hello()
{
std::cout << "hello" << std::endl;
}
};
class bar : private foo
{
public:
virtual ~bar()
{
// never run
std::cout << "bar destructor" << std::endl;
}
};
void need_foo(std::unique_ptr<foo> p)
{
p->hello();
}
int main()
{
auto && p = std::unique_ptr<foo>((foo *) new bar);
need_foo(std::move(p));
}
#include <iostream>
#include <vector>
/////////////////////////////////////////////////
// Write once, use again and again
//--->
// Inheritence policy to allow either poly or non-poly
enum class Policy { Polymorphic, NonPolymorphic };
template<Policy>
struct InheritencePolicy;
template <>
struct InheritencePolicy<Policy::Polymorphic>
{
virtual ~InheritencePolicy() = default;
};
template <>
struct InheritencePolicy<Policy::NonPolymorphic>
{
~InheritencePolicy() = default;
};
//--->
// Reusable interface - specialise for each STL container you wish to use
template <typename T, Policy P>
class ReusableInterface;
// specialised inteface for vector<T>
template<typename T, Policy P>
class ReusableInterface<std::vector<T>, P> : public InheritencePolicy<P>
{
public:
auto begin()
{
return cont_.begin();
}
auto end()
{
return cont_.end();
}
private:
std::vector<T> cont_;
};
template<typename T, Policy P>
using ReusableInterfaceVector = ReusableInterface<std::vector<T>, P>;
template<typename T>
using ReusableInterfaceVectorPoly = ReusableInterface<
std::vector<T>, Policy::Polymorphic
>;
template<typename T>
using ReusableInterfaceVectorNonPoly = ReusableInterface<
std::vector<T>, Policy::NonPolymorphic
>;
// add more specialisations here
/////////////////////////////////////////////////
// client code
class foo : public ReusableInterfaceVectorPoly<int>
{
public:
};
int main()
{
auto && o = foo();
auto && itr = o.begin();
}
class container: private std::vector<char>It won't compile, because the container class is not an std::vector<char> class, but it is implemented as an std::vector<char> class (the difference is subtile).
{
};
void foo(std::vector<char> const& in)
{
}
int main()
{
container myContainer;
foo(myContainer);
}
#include <vector>
class container: private std::vector<char> {
};
void foo(std::vector<char> const * p)
{
delete p;
}
int main()
{
// This cast is perfectly legal and -- sometimes -- even useful :)
std::vector<char> * p = (std::vector<char> *) new container;
foo(p);
}
#include <iostream>
#include <memory>
class bar
{
public:
~bar()
{
std::cout << "bar destructor" << std::endl;
}
};
class foo : private bar
{
public:
~foo()
{
std::cout << "container destructor" << std::endl;
}
};
int main()
{
{
// no pointer at all
foo myFoo;
}
{
// *sigh* raw pointers
foo* ptr{ new foo };
delete ptr;
}
{
// raw pointers 2
// bar* ptr = new foo; // does not compile, classes are not substitutable
// delete ptr;
}
{
// smart pointer
std::unique_ptr<foo> ptr{ std::make_unique<foo>() };
}
{
// smart pointer 2
// std::unique_ptr<bar> ptr = std::make_unique<container>(); // does not compile, classes are not substitutable
}
{
// smart pointer and move
std::unique_ptr<foo> ptr{ std::move(std::make_unique<foo>()) };
}
}
Both destructors are called every time.>> It is the less worst solution to ensure compatibility with very old code baseThe directive was put in place when namespaces were added to C++, and to prevent the excessive work of digging trough all the existing code to update them to the new standard.
I'm afraid I do not understand your point.
ASKER
>>>> Both destructors are called every time.Again no point in having a pointer(smart or not) to the base class, since with private inheritance, the derived class is not a base class, thus no dynamic types are involved.
>>Well of course, you're deleting by a pointer to the static and not dynamic type. The problem is if you delete via a pointer to the dynamic type and there is no virtual destructor (either explcit or implicit) in the dynamic class type.
The point is, at some point someone will do it and you'll end up (potentially) with a hard to locate defect.Careless codes are not my reponsibility.
C++ is an intermediate-level general-purpose programming language, not to be confused with C or C#. It was developed as a set of extensions to the C programming language to improve type-safety and add support for automatic resource management, object-orientation, generic programming, and exception handling, among other features.
TRUSTED BY
Open in new window