I have implemented Decorator pattern in C++ as follows:
#include <iostream>
#include <string>
#include <deque>
using namespace std;
// Abstract Component
template <class T>
class IArray
{
public:
virtual void insert(const T&) = 0;
virtual ~IArray(){}
};
// Concrete Component
template <class T>
class Array : public IArray<T>
{
public:
virtual void insert(const T& elem)
{
m_array.push_back(elem);
}
private:
deque<T> m_array;
};
// Decorator 1
template <class T>
class PositiveArray : public IArray<T>
{
public:
PositiveArray(IArray<T>* component):m_component(component)
{
}
virtual void insert(const T& elem)
{
if (elem > 0)
{
m_component->insert(elem);
}
else
{
cerr << "You can't insert non-positive number." <<endl;
}
}
private:
IArray<T>* m_component;
};
// Decorator 2
template <class T>
class PrintArray : public IArray<T>
{
public:
PrintArray(IArray<T>* component):m_component(component)
{
}
virtual void insert(const T& elem)
{
m_component->insert(elem);
cout << "Element " << elem << " was inserted into the array." <<endl;
}
private:
IArray<T>* m_component;
};
// Client
int main()
{
typedef int MyType;
PositiveArray<MyType> arr(new PrintArray<MyType>(new Array<MyType>));
arr.insert(10);
arr.insert(-10);
int i;
cin>>i;
return 0;
}
Now I want to have for all arrays printArray function. Should I write it as a pure virtual function in IArray and copy the following implementation of that function in each child of IArray?
void printArray()
{
for (int i = 0; i < m_array.size(); ++i)
{
cout << "elem " <<i << " is " << m_array[i] <<endl;
}
}
Is there any solution that can avoid of copying?
I would implement for_each_element in either Array, and expose the interface in IArray. It has 2 overloads that take std::function< void(T const&) > and std::function< void(T) > (second one is optional). Now PrintArray is a one line lambda function.
In C++03 you can use boost::function, and PrintArray is more annoying to write. So here it is less tempting.
As another approach, expose const_iterators to the underlying data.
As an aside, deque performance is surprisingly poor. As yet, there is nothing in your code that would make me think you could not use a std::vector. If you guaranteed memory contiguity, you could even have your const_iterators be T const* and expose the interface directly from IArray (with the implementation in Array). for_each_element becomes a two-liner in C++11, and PrintArray even without C++11 or for_each_element is 2 lines, and either implemented inline in IArray or as a free function.
Oh, and I'd make PrintArray a free function rather than a member function. for_each_element may need to be a member function, but you should be able to PrintArray without access to private data, once you expose iterators and/or for_each_element.
Related
I'm trying to store and manipulate a list of template class objects with different parameter types; the template class has two parametrised methods, one returning the parameter type and a void one accepting it as input.
More specifically, I have a template class defined as follows:
template<typename T>
class Test
{
public:
virtual T a() = 0;
virtual void b(T t) = 0;
};
And different specifications of it, such as:
class TestInt : public Test<int>
{
public:
int a() {
return 1;
}
void b(int t) {
std::cout << t << std::endl;
}
};
class TestString : public Test<std::string>
{
public:
std::string a() {
return "test";
}
void b(std::string t) {
std::cout << t << std::endl;
}
};
I'd like to be able to store in one single list different objects of both TestInt and TestString type and loop through it calling one method as input for the other, as in:
for (auto it = list.begin(); it != list.end(); ++it)
(*it)->b((*it)->a());
I've looked into boost::any but I'm unable to cast the iterator to the specific class, because I don't know the specific parameter type of each stored object. Maybe this cannot be done in a statically typed language as C++, but I was wondering whether there could be a way around it.
Just for the sake of completeness, I'll add that my overall aim is to develop a "parametrised observer", namely being able to define an observer (as with the Observer Pattern) with different parameters: the Test class is the observer class, while the list of different types of observers that I'm trying to properly define is stored within the subject class, which notifies them all through the two methods a() and b().
The virtuals have actually no meaning here, since for each T the signatures are distinct.
So it seems you have Yet Another version of the eternal "how can we emulate virtual functions templates" or "how to create an interface without virtual functions":
Generating an interface without virtual functions?
How to achieve "virtual template function" in C++
The first one basically contains an idea that you could employ here.
Here's an idea of what I'd do:
Live On Coliru
#include <algorithm>
#include <iostream>
namespace mytypes {
template <typename T>
struct Test {
T a() const;
void b(T t) { std::cout << t << std::endl; }
};
template <> int Test<int>::a() const { return 1; }
template <> std::string Test<std::string>::a() const { return "test"; }
using TestInt = Test<int>;
using TestString = Test<std::string>;
}
#include <boost/variant.hpp>
namespace mytypes {
using Value = boost::variant<int, std::string>;
namespace detail {
struct a_f : boost::static_visitor<Value> {
template <typename T>
Value operator()(Test<T> const& o) const { return o.a(); }
};
struct b_f : boost::static_visitor<> {
template <typename T>
void operator()(Test<T>& o, T const& v) const { o.b(v); }
template <typename T, typename V>
void operator()(Test<T>&, V const&) const {
throw std::runtime_error(std::string("type mismatch: ") + __PRETTY_FUNCTION__);
}
};
}
template <typename O>
Value a(O const& obj) {
return boost::apply_visitor(detail::a_f{}, obj);
}
template <typename O, typename V>
void b(O& obj, V const& v) {
boost::apply_visitor(detail::b_f{}, obj, v);
}
}
#include <vector>
int main()
{
using namespace mytypes;
using AnyTest = boost::variant<TestInt, TestString>;
std::vector<AnyTest> list{TestInt(), TestString(), TestInt(), TestString()};
for (auto it = list.begin(); it != list.end(); ++it)
b(*it, a(*it));
}
This prints
1
test
1
test
Bonus Points
If you insist, you can wrap the AnyTest variant into a proper class and have a() and b(...) member functions on that:
Live On Coliru
int main()
{
using namespace mytypes;
std::vector<AnyTest> list{AnyTest(TestInt()), AnyTest(TestString()), AnyTest(TestInt()), AnyTest(TestString())};
for (auto it = list.begin(); it != list.end(); ++it)
it->b(it->a());
}
Expanding on my comment above, the simplest what I can currently think of to achieve what you are trying to do - at least as I understood it from your example code - is the following:
/* Interface for your container, better not forget the destructor! */
struct Test {
virtual void operate(void) = 0;
virtual ~Test() {}
};
/* Implementation hiding actual type */
template<typename T>
struct TestImpl : public T, public Test {
void operate(void) {
T::b(T::a());
}
};
/* Actual code as template policies */
struct IntTest {
int a(void) {
return 42;
}
void b(int value) {
std::cout << value << std::endl;
}
};
struct StringTest {
std::string a(void) {
return "Life? Don't talk to me about life.";
}
void b(std::string value) {
std::cout << value << std::endl;
}
};
You would then need to create a container for objects of class Test and fill it with objects of the respective TestImpl<IntTest>, TestImpl<StringTest>, and so on. To avoid object slicing you need reference or pointer semantics, that is std::vector<std::unique_ptr<Test> > for example.
for (auto it = list.begin(); it != list.end(); ++it) {
(*it)->operate();
}
I have this structure of classes.
class Interface {
// ...
};
class Foo : public Interface {
// ...
};
template <class T>
class Container {
// ...
};
And I have this constructor of some other class Bar.
Bar(const Container<Interface> & bar){
// ...
}
When I call the constructor this way I get a "no matching function" error.
Container<Foo> container ();
Bar * temp = new Bar(container);
What is wrong? Are templates not polymorphic?
I think the exact terminology for what you need is "template covariance", meaning that if B inherits from A, then somehow T<B> inherits from T<A>. This is not the case in C++, nor it is with Java and C# generics*.
There is a good reason to avoid template covariance: this will simply remove all type safety in the template class. Let me explain with the following example:
//Assume the following class hierarchy
class Fruit {...};
class Apple : public Fruit {...};
class Orange : public Fruit {...};
//Now I will use these types to instantiate a class template, namely std::vector
int main()
{
std::vector<Apple> apple_vec;
apple_vec.push_back(Apple()); //no problem here
//If templates were covariant, the following would be legal
std::vector<Fruit> & fruit_vec = apple_vec;
//push_back would expect a Fruit, so I could pass it an Orange
fruit_vec.push_back(Orange());
//Oh no! I just added an orange in my apple basket!
}
Consequently, you should consider T<A> and T<B> as completely unrelated types, regardless of the relation between A and B.
So how could you solve the issue you're facing? In Java and C#, you could use respectively bounded wildcards and constraints:
//Java code
Bar(Container<? extends Interface) {...}
//C# code
Bar<T>(Container<T> container) where T : Interface {...}
The next C++ Standard (known as C++1x (formerly C++0x)) initially contained an even more powerful mechanism named Concepts, that would have let developers enforce syntaxic and/or semantic requirements on template parameters, but was unfortunately postponed to a later date. However, Boost has a Concept Check library that may interest you.
Nevertheless, concepts might be a little overkill for the problem you encounter, an using a simple static assert as proposed by #gf is probably the best solution.
* Update: Since .Net Framework 4, it is possible to mark generic parameters has being covariant or contravariant.
There are two problems here: default constructions have the form MyClass c;; with parentheses it looks like a function declaration to the compiler.
The other problem is that Container<Interface> is simply a different type then Container<Foo> - you could do the following instead to actually get polymorphism:
Bar::Bar(const Container<Interface*>&) {}
Container<Interface*> container;
container.push_back(new Foo);
Bar* temp = new Bar(container);
Or of course you could make Bar or its constructor a template as Kornel has shown.
If you actually want some type-safe compile-time polymorphism, you could use Boost.TypeTraits is_base_of or some equivalent:
template<class T>
Bar::Bar(const Container<T>& c) {
BOOST_STATIC_ASSERT((boost::is_base_of<Interface, T>::value));
// ... will give a compile time error if T doesn't
// inherit from Interface
}
No. Imagine that the container parameter is "hardcoded" into the class it defines (and that is actually how it works). Hence the container type is Container_Foo, that is not compatible with Container_Interface.
What you might try however is this:
template<class T>
Bar(const Container<T> & bar){
...
}
Yet you loose direct type checking that way.
Actually the STL way (probably more effective and generic) would be to do
template<class InputIterator>
Bar(InputIterator begin, InputIterator end){
...
}
... but I assume you don't have iterators implemented in the container.
It is possible to create an inheritance tree for containers, reflecting the inheritance tree of the data. If you have the following data:
class Interface {
public:
virtual ~Interface()
{}
virtual void print() = 0;
};
class Number : public Interface {
public:
Number(int value) : x( value )
{}
int get() const
{ return x; }
void print()
{ std::printf( "%d\n", get() ); };
private:
int x;
};
class String : public Interface {
public:
String(const std::string & value) : x( value )
{}
const std::string &get() const
{ return x; }
void print()
{ std::printf( "%s\n", get().c_str() ); }
private:
std::string x;
};
You could also have the following containers:
class GenericContainer {
public:
GenericContainer()
{}
~GenericContainer()
{ v.clear(); }
virtual void add(Interface &obj)
{ v.push_back( &obj ); }
Interface &get(unsigned int i)
{ return *v[ i ]; }
unsigned int size() const
{ return v.size(); }
private:
std::vector<Interface *> v;
};
class NumericContainer : public GenericContainer {
public:
virtual void add(Number &obj)
{ GenericContainer::add( obj ); }
Number &get(unsigned int i)
{ return (Number &) GenericContainer::get( i ); }
};
class TextContainer : public GenericContainer {
public:
virtual void add(String &obj)
{ GenericContainer::add( obj ); }
String &get(unsigned int i)
{ return (String &) GenericContainer::get( i ); }
};
This is not the best performing code; it is just to give an idea. The only problem with this approach is that every time you add a new Data class, you have to also create a new Container. Apart from that, you have polymorphism "working again". You can be specific or general:
void print(GenericContainer & x)
{
for(unsigned int i = 0; i < x.size(); ++i) {
x.get( i ).print();
}
}
void printNumbers(NumericContainer & x)
{
for(unsigned int i = 0; i < x.size(); ++i) {
printf( "Number: " );
x.get( i ).print();
}
}
int main()
{
TextContainer strContainer;
NumericContainer numContainer;
Number n( 345 );
String s( "Hello" );
numContainer.add( n );
strContainer.add( s );
print( strContainer );
print( numContainer );
printNumbers( numContainer );
}
I propose the following workaround, which employs a template function. Although the example use Qt's QList, nothing prevents the solution from being straightforwardly transposed to any other container.
template <class D, class B> // D (Derived) inherits from B (Base)
QList<B> toBaseList(QList<D> derivedList)
{
QList<B> baseList;
for (int i = 0; i < derivedList.size(); ++i) {
baseList.append(derivedList[i]);
}
return baseList;
}
Pros:
general
type-safe
fairly efficient if the items are pointers or some other cheaply copy-constructible elements (such as implicitly shared Qt classes)
Cons:
requires the creation of a new container, as opposed to enabling the reuse of the original one
implies some memory and processor overhead both to create and to populate the new container, which depend heavily on the cost of the copy-constructor
#include <iostream>
#include <sstream>
#include <map>
#include <vector>
struct Base { int b = 111; };
struct Derived: public Base { };
struct ObjectStringizer {
template <typename T>
static std::string to_string(const T& t) {
return helper<T>()(t);
}
template <typename T, typename = void>
struct helper {
std::string operator()(const T& t) {
std::ostringstream oss;
oss << t;
return oss.str();
}
};
template <typename T>
struct helper<T, typename std::enable_if<std::is_base_of<Base, T>::value>::type> {
std::string operator()(const T& base) {
return to_string(base.b);
}
};
template <typename T>
struct helper<std::vector<T>> {
std::string operator()(const std::vector<T>& v) {
std::ostringstream oss;
for (size_t i = 0, sz = v.size(); i < sz; ++i) {
oss << (i ? "," : "") << to_string(v[i]);
}
return "[" + oss.str() + "]";
}
};
template <typename Key, typename Value>
struct helper<std::map<Key, Value>> {
std::string operator()(const std::map<Key, Value>& m) {
std::ostringstream oss;
for (auto iter = m.begin(), iter_end = m.end(); iter_end != iter; ++iter) {
oss << (m.begin() != iter ? "," : "") << to_string(iter->first) << ":" << to_string(iter->second);
}
return "{" + oss.str() + "}";
}
};
};
int main(int argc, char* argv[]) {
std::cout << ObjectStringizer::to_string("hello ") << ObjectStringizer::to_string(std::string("world")) << std::endl;
std::cout << ObjectStringizer::to_string(Derived()) << std::endl;
std::cout << ObjectStringizer::to_string(std::vector<int>{3, 5, 7, 9}) << std::endl;
std::cout << ObjectStringizer::to_string(std::map<int, std::string>{{1, "one"}, {2, "two"}}) << std::endl;
return 0;
}
container is a container of Foo objects not a container of Interface objects
And it cannot be polymorphic either, pointers to things can be ,but not the objects themselvs. How big would the slots in the container have to be for container if you could put anything derived from interface in it
you need
container<Interface*>
or better
container<shared_ptr<Interface> >
I have the goal to make a base class, and a CRTP subbase class containing a static vector that will hold different values for each Derived class. However each object from the derived class must be able to see only one vector for the entire class. Moreover, I need to manipulate this vector through a common interface, this is why I am setting up a Base class.
Base class and subbase
class Seq {
public:
virtual unsigned long int elem(int i) = 0;
virtual void print(ostream& os) =0; // print out to a ostream
virtual int length() const =0;// return size of vector
virtual ~Seq() {}
protected:
virtual void gen_elems(int i) = 0; //generates elements
};
template<class T>
class subSeq: public Seq {
public:
unsigned long int elem(int i);
void print(ostream& os);
int length() const {return (int)memory.size();}
virtual ~subSeq() {}
protected:
static vector<long int> memory;
virtual void gen_elems(int i) = 0;
};
template<class T>
void subSeq<T>::print(ostream& os) {
if((int)memory.size() != 0) {
cout << "Stored numbers: ";
for(int i=0; i<(int)memory.size(); i++) {
os << memory[i] << " ";
}
cout << "\n";
} else {
cout << "Empty class!!\n";
}
}
template<class T>
unsigned long int subSeq<T>::elem(int i) {
if( i>=(int)memory.size() ) gen_elems(i);
return memory[i];
}
One of my derived classes:
class Fibonnacci: public subSeq<Fibonnacci> {
public:
Fibonnacci(int=0);
~Fibonnacci() {}
protected:
void gen_elems(int i); // Gera os elementos da série até o iésimo elemento (protected)
};
and its implementation:
Fibonnacci::Fibonnacci(int param) { if(param) gen_elems(param); }
void Fibonnacci::gen_elems(int param) {
for(int i=(int)memory.size(); i<param; i++) {
if(i>1) memory.push_back((long int)memory[i-1]+memory[i-2]);
else memory.push_back(1);
}
}
the problem occurs around this line
if(i>1) memory.push_back((long int)memory[i-1]+memory[i-2]);
compiler yells at me for
undefined reference to `subSeq<Fibonnacci>::memory'
this has been going on for hours, and since I am new to the concept CRTP, I see I don't understand it well and need help of people more capable than me.
Could someone enlighten me to what the problem is?
The member
template <>
vector<long int> subSeq<Fibonnacci>::memory;
Should be defined somewhere. To achieve your desired result, you should do this explicitly yourself in only a single translation unit (cpp file).
Or alternatively;
template <class T>
vector<long int> subSeq<T>::memory = {};
As some compilers do support common data folding (e.g COMDAT in msvc) which may help if you wish to use implicit instantiations, note this answer for more detail on common symbols.
I would like some advice on how I can solve an interesting problem I have.
The problem is to have two storage containers, of which the user selects which one to use for the remainder of the program (edit: at runtime). The two containers are Vector and List and store an object type we are to define. These two containers can be accessed using any means you desire (pop/[i]/...) How would you go about solving this problem?
Below is my best (almost working) solution, but I would really like to see what solutions more skilled C++ professionals have. As previously stated, I am really interested if I am taking the right approach. I have more than typical free time this semester and I intend to use it to really improve my c++ abilities. Thanks for your feedback.
Version 1
To start, I have a boolean flag,
bool using_vector = true; // what storage container was selected?
Second comes my two containers,
list<Question> q_llist;
vector<Question> q_vec;
Third my implementations for accessing the containers,
(still haven't figured out how make get_question() work in a graceful way, and I am not fond of the current route I am taking at the moment)
const Question& get_question(){
Question q = (using_vector) ?
q_vec.back() : q_llist.back();
(using_vector) ?
q_vec.pop_back() : q_llist.pop_back();
return q;
}
int questions_size(){
return (using_vector) ?
q_vec.size() : q_llist.size();
}
void push_back_question(Question& q){
if(using_vector){
q_vec.push_back(q);
}else{
q_llist.push_back(q);
}
}
Version 2
Note: Please use the tag "#v2" when referencing.
I decided to attempt the polymorphism approach. How does this implementation look?
/**
* using polymorphism to implement a parent class "Container"
* depending on user selection, reference C_Vec or C_List
*/
class Container {
protected:
list<Question> qlist;
vector<Question> qvec;
public:
void push_back(Question& q){/** do nothing */}
void pop_back(){/** do nothing */}
int size(){/** do nothing */}
Question& back(){/** do nothing */}
};
class C_Vec: public Container{
public:
void push_back(Question& q){qvec.push_back(q);}
void pop_back(){qvec.pop_back();}
int size(){return qvec.size();}
Question& back(){return qvec.back();}
};
class C_List: public Container{
public:
void push_back(Question& q){qlist.push_back(q);}
void pop_back(){qlist.pop_back();}
int size(){return qlist.size();}
Question& back(){return qlist.back();}
};
int main(){
Container *store;
char user_in;
cout << "Before we begin please select a storage container:" << endl
<< "a) Linked List" << endl
<< "b) Vector" << endl << ':';
cin >> user_in;
if(tolower(user_in) == 'a'){
C_List l;
store = &l;
}else{
C_Vec v;
store = &v;
}
}
You have several options. If you need to decide at runtime which container to use, polymorphism (inheritance) might work well.
#include <vector>
#include <list>
#include <memory>
struct Question {};
// runtime
struct Question_container {
virtual const Question& get_question() = 0;
virtual int questions_size() = 0;
virtual void push_back(const Question&) = 0;
virtual ~Question_container() = default;
};
struct Vector_question_container : Question_container {
const Question& get_question() override { return qv.back(); }
int questions_size() override { return qv.size(); }
void push_back(const Question& q) override { qv.push_back(q); }
private:
std::vector<Question> qv;
};
struct List_question_container : Question_container {
const Question& get_question() override { return qv.back(); }
int questions_size() override { return qv.size(); }
void push_back(const Question& q) override { qv.push_back(q); }
private:
std::list<Question> qv;
};
int main()
{
// some how figure out which container to use
std::unique_ptr<Question_container> qc{new Vector_question_container()};
}
If you can make the choice at compile-time, you could make the underlying sequence a template (or even template template) argument.
// CompileTime
template<typename Sequence>
struct Question_container_c {
const Question& get_question() { return s.back(); }
int questions_size() { return s.size(); }
void push_back(const Question& q) { s.push_back(q); }
private:
Sequence s;
};
int main()
{
Question_container_c<std::list<Question>> qlc;
Question_container_c<std::vector<Question>> qvc;
return 0;
}
Although you could also just make your algorithm work on iterators and leave the choice of the container to the user. This might be hard for some methods such as your push_back, but it doesn't actually do anything else then the normal push_back already provided.
To complement #pmr's answer, if you want to do it in an idiomatic way, you can create an adapter interface:
class IContainer {
public:
virtual ~IContainer() {}
virtual void push_back(const Question & q) = 0;
virtual void pop_back() = 0;
virtual const Question & back() const = 0;
virtual unsigned int size() const = 0;
};
And a generic implementation:
template <class T>
class Container: public IContainer {
private:
T m_container;
public:
virtual void push_back(const Question & q) {
m_container.push_back(q);
}
virtual void pop_back() {
m_container.pop_back();
}
virtual const Question & back() const {
return m_container.back();
}
virtual unsigned int size() const {
return m_container.size();
}
};
So you can do this:
std::unique_ptr<IContainer> pctr;
if (choice) {
pctr.reset(new Container<std::vector<Question>>);
}
else {
pctr.reset(new Container<std::list<Question>>);
}
std::cout << pctr->size();
I suppose the best way for your approach is to use iterators instead. Iterators are invented as a container abstraction in mind (sure thing, you can't abstract by 100% due different behavior of containers but anyway you have a solution better than nothing).
I'm working on a project where certain objects are referenced counted -- it's a very similar setup to COM. Anyway, our project does have smart pointers that alleviate the need to explicitly call Add() and Release() for these objects. The problem is that sometimes, developers are still calling Release() with the smart pointer.
What I'm looking for is a way to have calling Release() from the smart pointer create a compile-time or run-time error. Compile-time doesn't seem possible to me. I thought I had a run-time solution (see code below), but it doesn't quite compile either. Apparently, implicit conversion isn't allowed after using operator->().
Anyway, can anyone think of a way to accomplish what I'm trying to accomplish?
Many thanks for your help!
Kevin
#include <iostream>
#include <cassert>
using namespace std;
class A
{
public:
void Add()
{
cout << "A::Add" << endl;
}
void Release()
{
cout << "A::Release" << endl;
}
void Foo()
{
cout << "A::Foo" << endl;
}
};
template <class T>
class MySmartPtrHelper
{
T* m_t;
public:
MySmartPtrHelper(T* _t)
: m_t(_t)
{
m_t->Add();
}
~MySmartPtrHelper()
{
m_t->Release();
}
operator T&()
{
return *m_t;
}
void Add()
{
cout << "MySmartPtrHelper::Add()" << endl;
assert(false);
}
void Release()
{
cout << "MySmartPtrHelper::Release()" << endl;
assert(false);
}
};
template <class T>
class MySmartPtr
{
MySmartPtrHelper<T> m_helper;
public:
MySmartPtr(T* _pT)
: m_helper(_pT)
{
}
MySmartPtrHelper<T>* operator->()
{
return &m_helper;
}
};
int main()
{
A a;
MySmartPtr<A> pA(&a);
pA->Foo(); // this currently fails to compile. The compiler
// complains that MySmartPtrHelper::Foo() doesn't exist.
//pA->Release(); // this will correctly assert if uncommented.
return 0;
}
You can't do it - once you've overloaded the operator -> you're stuck - the overloaded operator will behave the same way reardless of what is rightwards of it.
You could declare the Add() and Release() methods private and make the smart pointer a friend of the reference-counting class.
operator-> has to return a pointer or an object which itself supports operator->. It can be recursive. What you can't do is to have operator-> behave differently based on what appears on the right hand side of the ->.
I can't think of any approach that doesn't involve somehow replicating the interfaces of your pointed-to objects, or require you to create objects publicly derived from your pointed to objects with Add and Release hidden and made private in the derived class and using a Base* pBase = pDerived; pBase->Add(); trick to call add and release from the smart pointer.
i got it to work by changing the overloaded operator in MySmartPtr and adding an overload operator in MySmartPtrHelper:
#include <iostream>
#include <cassert>
using namespace std;
class A
{
public:
void Add()
{
cout << "A::Add" << endl;
}
void Release()
{
cout << "A::Release" << endl;
}
void Foo()
{
cout << "A::Foo" << endl;
}
};
template <class T>
class MySmartPtrHelper
{
T* m_t;
public:
MySmartPtrHelper(T* _t)
: m_t(_t)
{
m_t->Add();
}
~MySmartPtrHelper()
{
m_t->Release();
}
operator T&()
{
return *m_t;
}
T* operator->()
{
return m_t;
}
void Add()
{
cout << "MySmartPtrHelper::Add()" << endl;
assert(false);
}
void Release()
{
cout << "MySmartPtrHelper::Release()" << endl;
assert(false);
}
};
template <class T>
class MySmartPtr
{
MySmartPtrHelper<T> m_helper;
public:
MySmartPtr(T* _pT)
: m_helper(_pT)
{
}
T* operator->()
{
return m_helper.operator->();
}
};
int main()
{
A a;
MySmartPtr<A> pA(&a);
pA->Foo();
//pA->Release(); // this will correctly assert if uncommented.
return 0;
}
Output:
macbook-2:~ $ ./a.out
A::Add
A::Foo
A::Release
I suggest you use something like the following code.
What you want is not possible unless you are willing to add a small constraint : objects must be copy-constructible (and you don't mind using this possibility). In this case, inheritance is a good way to go.
#include <iostream>
#include <cassert>
using namespace std;
template <class T>
class MySmartPtrHelper : public T
{
public:
MySmartPtrHelper(T* _t)
: m_t(*_t)
{
delete _t;
((T*) this)->Add();
}
~MySmartPtrHelper()
{
((T*) this)->Release();
}
void Add()
{
cout << "MySmartPtrHelper::Add()" << endl;
//will yield a compile-time error
BOOST_STATIC_ASSERT(false)
}
void Release()
{
cout << "MySmartPtrHelper::Release()" << endl;
//will yield a compile-time error
BOOST_STATIC_ASSERT(false)
}
};
template <class T>
class MySmartPtr
{
MySmartPtrHelper<T>* m_helper;
// Uncomment if you want to use boost to manage memory
// boost::shared_ptr<MySmartPtrHelper<T> > m_helper;
public:
MySmartPtr(T* _pT)
: m_helper(new MySmartPtrHelper<T>(_pT))
{
}
MySmartPtrHelper<T>* operator->()
{
return m_helper;
}
};
int main()
{
MySmartPtr<A> pA(new A());
pA->Foo();
//pA->Release(); // this will correctly assert if uncommented.
return 0;
}