Suppose I have a base class foo
class foo {
virtual int get() const = 0;
}
and maybe 20 sub-classes foo_1, foo_2 ... inherited from foo and in the form of:
class foo_1 : public foo {
int get() const { return 1; }
}
...
class foo_20 : public foo {
int get() const { return 20; }
}
Suddenly life is not so easy! I have a class foo_21, which has to do this:
class foo_21 : public foo {
int get() { member_ = false; return 0; }
bool member_;
}
The problem is get is declared as const in the base class, and I have to change
something in the sub-class foo_21. How could I find a way to go around it?
Your base function isn't virtual, which makes all this highly speculative. Your code should already be working as you posted it (though maybe not as you expect).
You could use mutable members:
class foo_21 : public foo
{
int get() const { member_ = false; return 0; }
mutable bool member_;
};
It's important that the mutable variable doesn't affect the logical constness of your class. If it does, you should rework your design.
Related
class A
{
friend void foo();
virtual void print_Var() const{};
};// does not contain variable Var;
template<class T>
class B : public A
{
T Var;
public:
B(T x):Var(x){}
void print_Var() const override
{
std::cout<<Var<<std::endl;
}
};
void foo()
{
std::array<std::unique_ptr<A>, 3> Arr = {
std::make_unique<B<int>>(100),
std::make_unique<B<int>>(20),
std::make_unique<B<std::string>>("Hello Stackoverflow")
};
std::shuffle(Arr.begin(), Arr.end(), std::mt19937(std::random_device()())); // 3rd parameter generated by Clang-Tidy
for (auto &i: Arr)
{
i->print_Var(); // OK
// auto z = i->Var // no member named Var in A
// obviously base class does not contain such variable
// if (i->Var==20) {/* do something*/}
// if (i->Var=="Hello Stackoverflow") {/* do something*/}
}
}
Explanation:
I want to iterate over array of pointers to A, which is filled with pointers to classes derived from A, and depending on what type is variable Var, do some if( ) statement.
Problem is that i cannot access Var, cause its not member of base class. However, it's possible to cout those values by, for example, overloaded function returning void. Could i write function in A class that returns templated type? like:
class A
{
<class T> GetVar()
}
Besides, I feel like I'm dealing with this problem in totally improper way. Can i mix templates and inheritance like that? If not, how should it be designed?
You have a few choices. I'll explain my preferred solution first.
1. Use dynamic dispatch
If you have an array of a base class type, why do you even want to do stuff with Var? That variable is specific to the child class. If you have a A somewhere, you shouldn't even care what B has or hasn't at that place.
Operations on the typed variable should be encapsulated in virtual function in the base class. If you want to do condition and stuff, maybe you could encapsulate that condition into a virtual function that returns a boolean.
2a. Drop the base class and use variant
Sometimes, you know in advance the amount of types that will go into that list. Using a variant and drop the base class is a good solution that may apply to your case.
Let's say you only have int, double and std::string:
using poly = std::variant<B<int>, B<double>, B<std::string>>;
std::array<poly, 3> arr;
arr[0] = B<int>{};
arr[1] = B<double>{};
arr[2] = B<std::string>{};
// arr[2] = B<widget>{}; // error, not in the variant type
std::visit(
[](auto& b) {
using T = std::decay_t<decltype(b)>;
if constexpr (std::is_same_v<B<int>, T>) {
b.Var = 2; // yay!
}
},
arr[0]
);
2b. Drop the base class and use generic functions
Drop the base class entirely, and template your functions that do operation on them. You can move all your function into an interface or many std::function. Operate on that instead of the function directly.
Here's an example of what I meant:
template<typename T>
void useA(T const& a) {
a.Var = 34; // Yay, direct access!
}
struct B {
std::function<void()> useA;
};
void createBWithInt() {
A<int> a;
B b;
b.useA = [a]{
useA(a);
};
};
This is fine for cases where you only have few operations. But it can quickly lead to code bloat if you have a lot of operations or if you have many types of std::function.
3. Use a visitor
You could create a visitor that dispatch to the right type.
This solution would be much close to what you except, but is quite combersome and can break easily when adding cases.
Something like this:
struct B_Details {
protected:
struct Visitor {
virtual accept(int) = 0;
virtual void accept(double) = 0;
virtual void accept(std::string) = 0;
virtual void accept(some_type) = 0;
};
template<typename T>
struct VisitorImpl : T, Visitor {
void accept(int value) override {
T::operator()(value);
}
void accept(double) override {
T::operator()(value);
}
void accept(std::string) override {
T::operator()(value);
}
void accept(some_type) override {
T::operator()(value);
}
};
};
template<typename T>
struct B : private B_Details {
template<typename F>
void visit(F f) {
dispatch_visitor(VisitorImpl<F>{f});
}
private:
virtual void dispatch_visitor(Visitor const&) = 0;
};
// later
B* b = ...;
b->visit([](auto const& Var) {
// Var is the right type here
});
Then of course, you have to implement the dispatch_visitor for each child class.
4. Use std::any
This is litteraly returning the variable with type erasure. You cannot do any operation on it without casting it back:
class A {
std::any GetVar()
};
I personnaly don't like this solution because it can break easily and is not generic at all. I would not even use polymorphism in that case.
I think it will be the easiest way. Just move the comparison method to the interface and override it in derived classes. Add the following lines to yor example:
class A
{
/*..................................................*/
virtual bool comp(const int) const { return false; }
virtual bool comp(const std::string) const { return false; }
virtual bool comp(const double) const { return false; }
};
template<class T>
class B : public A
{
/*..................................................*/
virtual bool comp(const T othr) const override { return othr == Var; }
};
void foo()
{
/*..................................................*/
if (i->comp(20))
{
/* do something*/
}
if (i->comp("Hello Stackoverflow"))
{
/* do something*/
}
/*..................................................*/
}
I have an example like the one below in C++ where I receive a pointer to base class, exampleParent, and would like to cast it to a pointer to the inherited class example (in reality I just want to call a function on example) . The caveat is that the inherited class is templated. In the example below, I know the template is of type int so there is no problem. In general, what would be a good way to do this if I am not aware before hand the type of the template?
class exampleParent{};
template<typename P>
class example: public exampleParent
{
public:
int do_something() const
{
std::cout<<"I am doing something"<<std::endl;
return 0;
}
};
boost::shared_ptr<const exampleParent> getPtr()
{
return boost::make_shared<const example<int>>();
}
int main()
{
boost::shared_ptr<const exampleParent> example = getPtr();
auto example_ptr = boost::dynamic_pointer_cast<const example<int>>(example);
return example_ptr-> do_something();
}
One solution I propose is to change the code to something like this:
class exampleParent{};
class something_interface: public exampleParent
{
public:
virtual int do_something() const = 0 ;
};
template<typename P>
class example: public something_interface
{
public:
int do_something() const override
{
std::cout<<"I am doing something"<<std::end;
return 0;
}
};
boost::shared_ptr<const exampleParent> getPtr()
{
return boost::make_shared<const example<int>>();
}
int main()
{
boost::shared_ptr<const exampleParent> example = getPtr();
auto example_ptr = boost::dynamic_cast<const something_interface>(example);
return example_ptr->do_something();
}
This would work, but it feels a bit of a hack: something_interface should not really exist, as it has no object oriented interpretation in itself.
Any help would be appreciated!
If you can make exampleParent an abstract class (if you can modify that class at all), that would be the best:
class exampleParent
{
public:
virtual ~exampleParent() = default;
virtual int do_something() const = 0;
};
template<typename P>
class example: public exampleParent
{
public:
int do_something() const override
{
std::cout<<"I am doing something"<<std::endl;
return 0;
}
};
Then you don't need a cast to invoke that method.
If you cannot touch this exampleParent class, go on with the intermediate one as you proposed, but remember to actually inherit exampleParent and don't throw exception, just make the method pure virtual:
class intermediate: public exampleParent
{
public:
~intermediate() override = default;
virtual int do_something() const = 0;
};
Otherwise the only way is to do dynamic_pointer_cast for all possible types and check the cast result, because different instances of template class are just different types in general. Of course it doesn't make sense if there is infinite number of possible template parameters P.
I got two classes:
class Foo {
public:
virtual int get() {
return 1;
}
};
class Bar : public Foo {
public:
int get() override {
return 2;
}
};
and now I got a pointer which points to a Bar object:
Foo* foo = new Bar;
now I want to call the get() which belongs to type Foo though pointer foo, as if the get() is not virtual, any way to do this?
Try: foo->Foo::get();
I hope that it won't be in the production code though. :)
I'm wondering if it is possible to make a class variable inaccessible inside this class? The only way to change the value of this variable will be through class setter. For example:
class foo
{
private:
int m_var;
bool m_isBig;
void setVar(int a_var)
{
// do something before setting value, like emitting signal
m_var = a_var;
}
void method()
{
int copy = m_var; // ok
m_var = 5; // error!
setVar(101); // ok
doSomething();
}
void doSomething()
{
if(m_var > 5)
{ m_isBig = true; }
else
{ m_isBig = false; }
}
};
I know that I could write another class only with setters and getter, but then I will don't have access to other methods/vars from class foo(encapsulation!). I think this could be a common problem, and there could be some design pattern for this, but I can't found any.
EDIT:
I edited the code to be clear, what I want to do in setter.
I'm not aware of a pattern for this, but one possibility is to wrap the member inside a nested class. I think this is also better style, since the creation of a new type expresses the intent that this member is not just an integer, but, instead, has unique behaviour.
class foo {
class MVar {
public:
MVar(foo* parent, int value = 0) : m_parent(parent), m_value(value) {}
MVar& operator=(const MVar&) = delete; // disable assignment
operator int() const { return m_var; }
void set(int new_value) {
// do something, possibly with m_parent
// nested classes have access to the parent's private members
m_value = new_value;
}
private:
foo* m_parent;
int m_value;
} m_var;
void method() {
int copy = m_var; // ok
m_var = 5; // error
MVar.set(101); // ok
}
};
This doesn't perfectly do what you want, since m_var doesn't really have type int, but it's something to consider.
You can't do exactly you're asking in C++. All variables in a class are visible to all methods in a class, regardless of whether they are public or private.
The question you want to ask yourself is: why would a class want to hide things from itself? The class's interface is the boundary between the class's internal implementation and the services it provides to the outside world. You're either inside the class or outside.
With this in mind, perhaps you use case is such that writing an additional class is the appropriate thing to do?
You can wrap the integer into a special class, and only define setVar(), but not an assignment operator taking an int
class M_type
{
int m_var;
public:
explicit M_type(int m) : m_var{m} {}
operator int() const { return m_var; }
void setVar(int a_var) { m_var = a_var; }
};
class foo
{
M_type m_var;
bool m_isBig;
public:
explicit foo(int m) : m_var{m} {};
void method()
{
int copy = m_var; // OK, calls operator int()
m_var = 5; // error, no operator=(int)
m_var.setVar(101); // OK, calls setVar(int)
doSomething();
}
void doSomething()
{
if(m_var > 5)
{ m_isBig = true; }
else
{ m_isBig = false; }
}
};
Make sure to give M_type an explicit constructor taking an int, and only an implicit conversion operator int() that acts as a "getter". If you make the constructor implicit as well, the compiler-generated assignment operator=(M_type const&) will be able to convert the argument 5 to an M_type.
I am using a factory class to produce a number of little classes from memory pools. These little classes are constant once they are returned by the factory.
Currently a typical declaration of one of these little objects goes something like this:
class LittleObject
{
public:
...//non-getter and setter member functions
int getMemberVariable1() const;//should be accessible to everyone
void setMemberVariable1(int newMemberVariable1Value);//should only be accessible to factory class
...//more getters and setters
private:
...
};
So, as you can see the getters and setters are both in the public area. But the only time the values should be set is during the time it is being built by the factory class. Now, I can clearly see one option where I move the setter functions to private access and make the factory a friend of the LittleObject class. I find this option a bit inelegant because it exposes other private member functions to the factory. Private member functions which the factory has no business accessing.
So my question is this: What is the best method making it so that only the factory class can use the setter functions?
I would use a friend class:
class LittleObject
{
friend class LittleObjectFactory;
public:
int getMemberVariable();
private:
void setMemberVariable( int value );
};
I would really prefer to friend the factory, but if you need stronger
encapsulation, at the expense of elegance, mabe it can be done
struct LittleData;
class Factory
{
public:
void MakeLittle(LittleData&);
};
struct LittleData
{
int data1;
float data2;
};
class LittleObject
{
public:
LittleObject(const LittleObject&) = default;
LittleObject& operator=(const LittleObject&) = default;
int GetData1() const { return data.data1; }
float GetData2() const { return data.data2; }
static LittleObject MakeOne( Factory& f )
{
LittleObject obj;
f.MakeLittle(obj.data);
return obj;
}
private:
LittleObject();
LittleData data;
};
Looking at what I just wrote... I really prefer friend
Another possibility is stencils.
By that I mean static instances of each LittleObject preset to the required configuration so that the factory simply needs to make a copy.
The copy can be made via the copy constructor or, if you don't want to make one of those (and the objects are trivial) then you could use memcpy().
Here is an example using copy constructors:
class LittleObject1
{
int a;
int b;
public:
LittleObject1(const LittleObject1& o): a(o.a), b(o.b) {}
LittleObject1(int a = 0, int b = 0): a(a), b(b) {}
static LittleObject1 stencil;
int get_a() const { return a; }
int get_b() const { return b; }
};
LittleObject1 LittleObject1::stencil(3, 7); // preset values
class LittleObject2
{
std::string s;
public:
LittleObject2(const LittleObject2& o): s(o.s) {}
LittleObject2(const std::string& s = ""): s(s) {}
static LittleObject2 stencil;
std::string get_s() const { return s; }
};
LittleObject2 LittleObject2::stencil("hello"); // preset values
class Factory
{
public:
template<typename Type>
Type* create() const
{
return new Type(Type::stencil); // make a copy of the preset here
}
};
int main()
{
Factory fact;
LittleObject1* o1 = fact.create<LittleObject1>();
std::cout << o1->get_a() << '\n';
std::cout << o1->get_b() << '\n';
LittleObject2* o2 = fact.create<LittleObject2>();
std::cout << o2->get_s() << '\n';
}
This would only be useful if the values are preset and don't need calculating at run-time.
Rely on const-correctness
You say the objects are constant when they are returned by the factory.
In that case why not just return const objects:
class Factory
{
public:
std::unique_ptr<const DynamicLittleObject> createDynamicLittleObject();
const AutomaticLittleObject createAutomaticLittleObject();
};
Then just ensuring to write their functionality in a const-correct way will give the correct access control.
Some might worry about the case the user might cast away the constness, but there's only so much that is worth doing to protect them from themselves.
You could make the factory a static member function of each object. So each object type knows how to create itself. Then you can have some kind of template function to make creating them a little less typing.
Something a bit like this:
class LittleObject1
{
int a = 0;
int b = 0;
public:
virtual ~LittleObject1() {}
static LittleObject1* create()
{
LittleObject1* o = new LittleObject1;
o->a = 1;
o->b = 2;
return o;
}
};
class LittleObject2
{
std::string s;
public:
virtual ~LittleObject2() {}
static LittleObject2* create()
{
LittleObject2* o = new LittleObject2;
o->s = "hello";
return o;
}
};
template<typename Type>
Type* createType(Type*)
{
return Type::create();
}
int main()
{
LittleObject1* o1 = createType(o1);
LittleObject2* o2 = createType(o2);
}