Given the following template:
template <typename T>
class wrapper : public T {};
What visible differences in interface or behaviour are there between an object of type Foo and an object of type wrapper<Foo>?
I'm already aware of one:
wrapper<Foo> only has a nullary constructor, copy constructor and assignment operator (and it only has those if those operations are valid on Foo). This difference may be mitigated by having a set of templated constructors in wrapper<T> that pass values through to the T constructor.
But I'm not sure what other detectable differences there might be, or if there are ways of hiding them.
(Edit) Concrete Example
Some people seem to be asking for some context for this question, so here's a (somewhat simplified) explanation of my situation.
I frequently write code which has values which can be tuned to adjust the precise performance and operation of the system. I would like to have an easy (low code overhead) way of exposing such values through a config file or the user interface. I am currently writing a library to allow me to do this. The intended design allows usage something like this:
class ComplexDataProcessor {
hotvar<int> epochs;
hotvar<double> learning_rate;
public:
ComplexDataProcessor():
epochs("Epochs", 50),
learning_rate("LearningRate", 0.01)
{}
void process_some_data(const Data& data) {
int n = *epochs;
double alpha = *learning_rate;
for (int i = 0; i < n; ++i) {
// learn some things from the data, with learning rate alpha
}
}
};
void two_learners(const DataSource& source) {
hotobject<ComplexDataProcessor> a("FastLearner");
hotobject<ComplexDataProcessor> b("SlowLearner");
while (source.has_data()) {
a.process_some_data(source.row());
b.process_some_data(source.row());
source.next_row();
}
}
When run, this would set up or read the following configuration values:
FastLearner.Epochs
FastLearner.LearningRate
SlowLearner.Epochs
SlowLearner.LearningRate
This is made up code (as it happens my use case isn't even machine learning), but it shows a couple of important aspects of the design. Tweakable values are all named, and may be organised into a hierarchy. Values may be grouped by a couple of methods, but in the above example I just show one method: Wrapping an object in a hotobject<T> class. In practice, the hotobject<T> wrapper has a fairly simple job -- it has to push the object/group name onto a thread-local context stack, then allow the T object to be constructed (at which point the hotvar<T> values are constructed and check the context stack to see what group they should be in), then pop the context stack.
This is done as follows:
struct hotobject_stack_helper {
hotobject_stack_helper(const char* name) {
// push onto the thread-local context stack
}
};
template <typename T>
struct hotobject : private hotobject_stack_helper, public T {
hotobject(const char* name):
hotobject_stack_helper(name) {
// pop from the context stack
}
};
As far as I can tell, construction order in this scenario is quite well-defined:
hotobject_stack_helper is constructed (pushing the name onto the context stack)
T is constructed -- including constructing each of T's members (the hotvars)
The body of the hotobject<T> constructor is run, which pops the context stack.
So, I have working code to do this. There is however a question remaining, which is: What problems might I cause for myself further down the line by using this structure. That question largely reduces to the question that I'm actually asking: How will hotobject behave differently from T itself?
Strange question, since you should be asking questions about your specific usage ("what do I want to do, and how does this help me or hurt me"), but I guess in general:
wrapper<T> is not a T, so:
It can't be constructed like a T. (As you note.)
It can't be converted like a T.
It loses access to privates T has access to.
And I'm sure there are more, but the first two cover quite a bit.
Suppose you have:
class Base {};
class Derived : Base {};
Now you can say:
Base *basePtr = new Derived;
However, you cannot say:
wrapper<Base> *basePtr = new wrapper<Derived>();
That is, even though their type parameters may have an inheritance relationship, two types produced by specialising a template do not have any inheritance relationship.
A reference to an object is convertible (given access) to a reference to a base class subobject. There is syntactic sugar to invoke implicit conversions allowing you to treat the object as an instance of the base, but that's really what's going on. No more, no less.
So, the difference is not hard to detect at all. They are (almost) completely different things. The difference between an "is-a" relationship and a "has-a" relationship is specifying a member name.
As for hiding the base class, I think you inadvertently answered your own question. Use private inheritance by specifying private (or omitting public for a class), and those conversions won't happen outside the class itself, and no other class will be able to tell that a base even exists.
If your inherited class has its own member variables (or at least one), then
sizeof(InheritedClass) > sizeof(BaseClass)
Related
We can overload functions by giving them a different number of parameters. For example, functions someFunc() and someFunc(int i) can do completely different things.
Is it possible to achieve the same effect on classes? For example, having one class name but creating one class if a function is not called and a different class if that function is not called. For example, If I have a dataStorage class, I want the internal implementation to be a list if only add is called, but want it to be a heap if both add and pop are called.
I am trying to implement this in C++, but I am curious if this is even possible. Examples in other languages would also help. Thanks!
The type of an object must be completely known at the point of definition. The type cannot depend on what is done with the object later.
For the dataStorage example, you could define dataStorage as an abstract class. For example:
struct dataStorage {
virtual ~dataStorage() = default;
virtual void add(dataType data) = 0;
// And anything else necessarily common to all implementations.
};
There could be a "default" implementation that uses a list.
struct dataList : public dataStorage {
void add(dataType data) override;
// And whatever else is needed.
};
There could be another implementation that uses a heap.
struct dataHeap : public dataStorage {
void add(dataType data) override;
void pop(); // Maybe return `dataType`, if desired
// And whatever else is needed.
};
Functions that need only to add data would work on references to dataStorage. Functions that need to pop data would work on references to dataHeap. When you define an object, you would choose dataList if the compiler allows it, dataHeap otherwise. (The compiler would not allow passing a dataList object to a function that requires a dataHeap&.) This is similar to what you asked for, except it does require manual intervention. On the bright side, you can use the compiler to tell you which decision to make.
A downside of this approach is that changes can get messy. There is additional maintenance and runtime overhead compared to simply always using a heap (one class, no inheritance). You should do some performance measurements to ensure that the cost is worth it. Sometimes simplicity is the best design, even if it is not optimal in all cases.
Classic way to get a reference to class member or its value we use getters like getValue(). Could this be an alternative way? :
class A{
ComplexClass value_;
public:
//No need. ComplexClass const& getValue() const { return value_; }
ComplexClass const& value = value_; /// ???
}
Will this work? How do you like such syntax?
UPD.
This point is to make user code simpler. Personally I better like auto x = a.value than auto x = a.getValue(). Of course this is a deal of taste.
Will this still work nice if:
class A{
public:
ComplexClass const& value = value_;
protected:
ComplexClass value_;
}
I ask because I met some troubles with one compiler.
One of the main reasons to prefer member functions over data members is flexibility and maintainability. If you only ever wrote some code once, perfectly, and it would never be changed or reused, then you could certainly have public data members that users refer to directly.
The interesting question is what happens when your code doesn't meet these criteria, e.g. if it is going to evolve, and if other people start using it. Then once you have a public data member, you are forced to always have that data member. Details of your class layout are now part of your public contract. Simple refactorings like moving common parts into nested member objects are no longer private and break existing users.
Your proposed reference data member adds almost no benefit over a public data member (except for in very trivial cases), and unlike member functions, non-static data members affect the class layout. Class layout is another thing you will probably want to keep stable once you have users, so that old, compiled libraries can continue to be linked against new user code. Member functions are much easier to evolve while keeping the data layout unchanged.
There's a nice example in the standard library where such a mistake was made: std::pair<T1, T2> is specified to contain public data members first and second. That means that all user specializations must adhere to the same specification, and cannot easily employ things like base layout optimizations. Had first and second been specified as member functions, such optimizations could be applied trivially.
In brief:
Is it possible to change the type of an object once established?
What I've tried:
For instance given the design:
(edit: To clarify, this is a simplified example of a strategy design pattern, it isn't important what ChangeData does, only that we can change what it does by changing _interface)
struct MyClass
{
int _data;
MyInterface* _interface;
void DoChangeData() { Interface->ChangeData(*this); }
};
MyClass x;
x._interface = new DerivedClass1();
x.DoChangeData(); // do something
x._interface = new DerivedClass2();
x.DoChangeData(); // do something else
switching _interface allows us to change the operations upon the class, however this necessitates creating wrapper methods (DoChangeData) and always passing the this pointer as an argument, which is ugly.
A better solution I would prefer is:
struct MyClass abstract
{
int _data;
virtual void ChangeData() = 0;
};
But here once the concrete class is established, unlike _interface, it cannot be changed. It seems like this should be possible providing the different derived classes don't add any new fields. Is there any way to implement the ChangeClass function below?
DerivedClass1 x;
x.DoChangeData(); // do something
x.ChangeClass(DerivedClass2); // ???
x.DoChangeData(); // do something else
Note I am talking about virtual classes, and reinterpret_cast only works with non-virtual objects. Copy constructors require the overhead of moving existing memory, which I would also rather avoid.
This looks like the kind of question that can be better answered if you explain the actual problem rather than how to implement your solution.
It is not clear to me what DoChangeData should do and why it requires a reference to MyClass.
The problem statement is not clear enough to get an answer, and the title (as stated) would get a no as an answer (in C++ you can not change types, is a strongly typed language), but I understand is not what you are asking.
Please clarify the question to be able to get a satisfying answer.
BTW, you may want to pay a look at the Visitor design pattern and/or the Strategy design pattern.
You could declare function pointers in MyClass and change them to change the type. Or create your own vtable with a (const pointer) to an array of function pointers, and just change this pointer to change the type.
I'm pushing IMO the limits of C++template programming. The system is an Arduino but my attempt is applicable to any microcontroller system.
I define Pins using a template class with an 'int' parameters
template<const int pin>
struct Pin {
Pin() { mode(pin, 0); }
};
template<const int pin>
class PinOut : public Pin<pin> {};
I can create template classes to use PinOut like:
template<typename F>
class M {
public:
M() { }
F mF;
};
M<PinOut<1>> m1;
template<int F>
class N {
public:
N() { }
Pin<F> mF;
};
N<1> n1;
But I'd like to not use templates in the classes that use PinOut. This is illustrative of my thinking showing possible approaches but clearly doesn't work.
class R {
public:
R(const int i) {
}
PinOut<i> mF; // create template instance here
};
R r1(1); // what I'd like to able to do
I recognize the problem is creating a type inside class R.
The other possibility is instantiating a PinOut variable and passing it in but again passing and creating a type inside the class is a problem. Something like this:
class S {
public:
S(PinOut<int>& p) { } // how to pass the type and instance
PinOut<p>& mF; // and use it here
};
PinOut<1> pp;
S s1(pp);
Sorry if this sound abrupt but please don't ask why or what I'm trying to do. This is an experiment and I'm pushing my understanding of C++ especially templates. I know there are other approaches.
Yes, any function that takes that type must itself be a template.
But is the entire family of Pin related in a way that some thing are meaningful without knowing T? This can be handled with a base class that's a non-template. The base class idea is especially handy because it can contain virtual functions that do know about T. This lets you switch between compile-time and run-time polymorphism on the fly as desired. Taken to an extreme, that becomes the weaker idea with the same syntax of "Generics" as seen in Java and .NET.
More generally, this is a concept known as type erasure. You might search for that term to find out more. It is designed into libraries in order to keep common code common and prevent gratuitous multiplication of the same passage though multiple instantiations.
In your case, pin is a non-type argument, which is something Generics don't even do. But it may not really affect the type much at all: what about the members change depending on pin? This might be an array bound, or a compile-time constant used to provide compile-time knowledge and optimization, or there for the sole purpose of making the type distinct.
All of these cases are things can be dealt with at run-time, too. If it's for the sole purpose of making the type distinct (e.g. make the compiler check that you pass time values and distance values to the correct parameters) then the real guts are all in a base class that omits the distinctiveness.
If it's an array bound or other type difference that can be managed at run-time, then again the base class or an adapter/proxy can do it at run-time. More generally a compile-time constant that doesn't affect the class layout can be known at run-time with the same effect, just less optimization.
From your example, that it is sensible to make the pin a constructor argument, the class could be implemented in the normal way with run-time configuration. Why is it a template? Presumably for compile-time checking to keep separate things separate. That doesn't cause them to work in different ways, so you want that compile-time part to be optional. So, this is a case where a base class does the trick:
class AnyPin
{
public:
AnyPin (int pin); // run-time configuration
};
template <int pin>
class Pin : public AnyPin { ⋯ };
Now you can write functions that take AnyPin, or write functions that take Pin<5> and get compile-time checking.
So just what does pin do to the class, in terms of its layout and functionality? Does it do anything that makes it unacceptable to just implement it as a run-time constructor value?
You ask that we don't inquire as to what you're trying to do, but I must say that templates have certain features and benefits, and there must be some reason for making it a template. Speaking simply in language-centric terms, did I miss something with the above analysis? Can you give a C++-programming reason for wanting it to be a template, if my summary didn't cover it? That may be why you didn't get any answers thus far.
I am struggling to understand why the initialization of pprocessor, below, is written like this:
class X
{
...
private:
boost::scoped_ptr<f_process> pprocessor_;
};
X:X()
: pprocessor_( f_process_factory<t_process>().make() ) //why the factory with template
{...}
instead of just writing
X:X()
: pprocessor_( new t_process() )
{...}
Other relevant code is:
class f_process {
...
};
class t_process : public f_process {
...
};
//
class f_process_factory_base {
public:
f_process_factory_base() { }
virtual ~f_process_factory_base() = 0 { }
virtual f_process* make() = 0;
};
template < typename processClass >
class f_process_factory : public f_process_factory_base {
public:
f_process_factory() { }
virtual ~f_process_factory() { }
virtual processClass* make() { return new processClass(); }
};
The guy who wrote the code is very clever so perhaps there is a good reason for it.
(I can't contact him to ask)
As it is, it seems kinda pointless, but I can think of a few possible uses that aren't shown here, but may be useful in the future:
Memory management: It's possible that at some point in the future the original author anticipated needing a different allocation scheme for t_process. For example, he may want to reuse old objects or allocate new ones from an arena.
Tracking creation: There may be stats collected by the f_process_factory objects when they're created. Maybe the factory can keep some static state.
Binding constructor parameters: Perhaps a specialization of the f_process_factory for t_process at some point in the future needs to pass constructor parameters to the t_process creator, but X doesn't want to know about them.
Preparing for dependency injection: It might be possible to specialize these factories to return mocks, instead of real t_process. That could be achieved in a few ways, but not exactly as written.
Specialized object creation: (This is really just the general case for the previous two), there may be specializations of t_process that get created in different circumstances - for example, it might create different t_process types based on environmental variables or operating system. This would require specializations of the factory.
If it were me, and none of these sound plausible, I'd probably rip it out, as it seems like gratuitous design pattern usage.
This look like he is using the factory design pattern to create new instances of t_process. This will allow you to delegate the responsibility of creating different types of t_process away from class X
Well, in this case it doesn't make much sense, unless the author expects the default factory's definition will be updated sometime in the future. It would make sense, though, if the factory object were passed in as a parameter; a factory gives you more flexibility in constructing an object, but if you instantiate the factory at the same place that you use it, then it really doesn't provide an advantage. So, you're right.