Class inheritance - stacking methods - c++

I have seen this once, but I can't remember how to make it work again. Let's say I have three classes:
class CRoot { ... };
class CLevelOne { ... };
class CLevelTwo { ... };
Now, I have main function, where I'd like to go more in depth by using this syntax:
int main (void)
{
CRoot myRoot ("This is root.");
myroot.AddLevelOne("This is level one.").AddLevelTwo("This is level two.");
}
So the final construction of my classes looks like this:
+- This is root.
|+- This is level one.
||+- This is level two.
How to implement it so I can use syntax something.Method1().Method2().MethodN(). ...; ?

Try this:
struct Level2
{
// See class Level1 below
};
struct Level1
{
std::string m_name;
boost::shared_ptr<Level2> p_level2;
Level1(const std::string name)
: name(m_name)
{ ; }
Level2& add_level_two(const std::string& name)
{
p_level2 = new Level2(name);
}
};
struct Root
{
boost::shared_ptr<Level1> p_level1;
Level1& add_level_one(const std::string& name)
{
p_level1 = new Level1(name);
}
};
With a little more thought, a base class, one could create this more generically. Also the level numbers would have to be moved out of the method names.

Something like this:
struct CLevelTwo { };
struct CLevelOne {
CLevelTwo * AddLevelTwo() {
return new CLevelTwo();
}
};
struct CRoot {
CLevelOne * AddLevelOne() {
return new CLevelOne();
}
};
int main(){
CRoot *root = new CRoot();
root->AddLevelOne()->AddLeveTwo();
}
You can replace the pointers with references, but beware of memory leaks. Note that this code leaks too, but it is more manageable and managing lifetime of the objects should not be a big problem.

Just make SomeMethod return a reference of *this:
struct Foo
{
Foo& Add(SomeOtherThing& thing)
{
// Do the "add"...
return *this;
}
};
Now you can do:
Foo myFoo;
myFoo.Add(...).Add(...).Add(...);
It's just like how the assignment operator overload works.

Edit After reviewing this with Thibaut, I propose the following solution:
class Node
{
private:
std::string _name;
std::list<Node*> _nodes;
public:
Node(const std::string& name) : _name(name)
{
}; // eo ctor
virtual ~Node()
{
for(std::list<Node*>::iterator it(_nodes.begin());
it != _nodes.end();
++it);
delete *it;
}; // eo dtor
Node* Add(const std::string& name)
{
Node* newNode = new Node(name);
_nodes.Add(newNode);
return newNode;
}; // eo Add
}; // eo class Node

Related

create two pointers for template class and work with current selected possible?

I'll try showing what I want with an example code:
template <typename T>
class myclass
{
public:
myclass(int x, int y);
// code
};
main()
{
myclass<cat>* ptr1 = NULL;
myclass<dog>* ptr2 = NULL;
if (/*condition*/)
{
ptr1 = new myclass<cat>(1,1);
delete ptr2;
current_ptr = ptr1; // how to declare
}
else
{
ptr2 = new myclass<dog>(1,2);
delete ptr1;
current_ptr = ptr2; // how to declare
}
current_ptr->some_method(); //work with it
}
I want use template class with different arguments. How do that?
Templates are a compile time construct. When the template is instantiated, it creates unrelated classes.
As such, myclass<cat> and myclass<dog> are totally different, unrelated classes with you cannot exchange pointers between them.
To mix them up at runtime, you need some form of runtime polymorphism. The simplest is when you know all types in advance, then you can use variants:
#include <variant>
int main() {
std::variant<myclass<cat>, myclass<dog>> obj;
if (/* runtime condition */) {
obj = myclass<cat>{};
} else {
obj = myclass<dog>{};
}
// work with it:
std::visit(
[](auto const& myclass_obj) {
// in here, myclass_obj is either a myclass<cat> or myclass<dog>
// So the code has to be valid for both, unless using if constexpr.
if constexpr (std::is_same_v<decltype(myclass_obj), myclass<cat> const&>) {
// cat specific code
} else {
// dog specific code
}
},
obj
);
}
If you want to continue with pointers, you need a base class:
class mybase {
public:
virtual ~mybase() = default;
virtual someMethod() = 0;
};
template<typename T>
class myclass : public mybase {
public:
myclass(int x, int y) {}
void someMethod() override {
}
};
Then declare your pointer:
mybase* ptr = nullptr;

Move assignment with base class and derived class

Below is a downsized implementation of a two classes I'm having trouble with.
code:
Here is the base class:
//header
class Script
{
public:
Script(const QString& path, int timeout=10000) :
mPath(path), mTimeout(timeout), script(new QProcess) {}
Script(Script&& s);
Script& operator=(Script&& s);
virtual ~Script();
protected:
QString mPath;
int mTimeout;
QProcess* script;
}
//source
Script::Script(Script&& s) :
mPath(s.mPath), mTimeout(s.Timeout), script(s.script)
{
s.script = nullptr;
}
Script& Script::operator=(Script&& s){
if(&s != this){
delete script;
script = s.script;
s.script = nullptr;
mPath = s.mPath;
mTimeout = s.mTimeout;
}
return *this;
}
Script::~Script() {
delete script;
script = nullptr;
}
From the code snippet above I derive the following class:
//header
class ConfigurationScript : public Script
{
public:
ConfigurationScript(const QString& path);
ConfigurationScript(ConfigurationScript&& s);
ConfigurationScript& operator=(ConfigurationScript&& s);
}
//source
ConfigurationScript::ConfigurationScript(const QString& path) :
Script(path) {}
ConfigurationScript::ConfigurationScript(ConfigurationScript&& s) :
Script(std::move(s)) {}
ConfiguratonScript& ConfigurationScript::operator=(ConfigurationScript&& s) {
if(&s != this){
delete script;
script = s.script;
s.script = nullptr;
mPath = s.mPath;
mTimeout = s.mTimeout;
}
return *this;
}
question:
The move assignment of ConfigurationScript contains duplicate code when you compare it to the move assignment of its base class Script. Can you call the assignment operator of the base class to overcome duplicate code?
For instance is something like this valid?
ConfigurationScript& ConfigurationScript::operator=(ConfigurationScript&& s) {
if(&s != this){
Script::operator=(s);
}
return *this;
}
The return type of Script::operator=(s) is Script, do I need to cast it to a ConfigurationScript?
If the above is valid, I fail to see how it works. Otherwise, is there a way to avoid code duplication?
Yes, it's valid, and you don't need to cast anything.
You're not even using the result of the base op= call, but you know that it is a Script& that refers to the current object. Since you already have a ConfigurationScript& that refers to the current object and has the needed type (i.e. *this), there is nothing more to do.
In fact, this is so natural that you can just let the compiler do it for you:
#include <iostream>
#include <utility>
struct Base
{
Base& operator=(Base&& other)
{
std::cout << "YOLO!\n";
return *this;
}
};
struct Derived : Base
{
/*
// Don't need this
Derived& operator=(Derived&& other)
{
Base::operator=(std::move(other));
return *this;
}*/
/*
// Or even this (though you may need to introduce it
// if you have some other user-declared stuff)
Derived& operator=(Derived&& other) = default;
*/
};
int main()
{
Derived d1, d2;
d2 = std::move(d1);
}
// Output: YOLO!
(live demo)
However I think you probably meant Script::operator=(std::move(s)) to get true movement rather than a copy.

Is it possible to have pointer to unordered_set<MyClass> as a part of myClass?

My code looks like that:
class Node : public bitset<BITS_COUNT> {
public:
Node(string s) : bitset<BITS_COUNT>(s) {}
void setGroup(unordered_set<Node>* newSet) { currentGroup = newSet; }
unordered_set<Node>* getCurrentSet() { return currentGroup; }
private:
unordered_set<Node>* currentGroup = nullptr;
};
But complier doesn't allow me to do this, since there is no hash function defined for class Node. I'd like it to use hash function from base class, so I did this:
namespace std
{
template<>
struct hash<Node>
{
size_t operator()(const Node& k) const
{
return k.hash();
}
};
}
But it still doesn't work. If I put this before Node delcaration, k.hash() is undefined (and I can't forward declare Node: public bitset<> since it isn't possible). If I put this after class declaration I get error that there is no hash function for class Node.
How can I solve this problem?
Thanks Frank, your comment is actually a solution for me. If someone needs the code it looks like this:
namespace std
{
template<>
struct hash<Node>
{
size_t operator()(const Node& k) const;
};
}
class Node : public std::bitset<BITS_COUNT> {
public:
Node(std::string s) : bitset<BITS_COUNT>(s) {}
void setGroup(std::unordered_set<Node>* newSet) { currentGroup = newSet; }
std::unordered_set<Node>* getCurrentSet() { return currentGroup; }
private:
std::unordered_set<Node>* currentGroup = nullptr;
};
namespace std
{
size_t hash<Node>::operator()(const Node& k) const
{
return k.hash();
}
}

C++ dynamic properties

I don't know if dynamic properties is really the right term, but I want to be able to define properties at run-time via some container. The usage I'd be looking for would be something like the following:
Properties p;
p.Add<int>("age", 10);
int age = p.Get<int>("age");
I can't seem to work this out because the container of each setting would need to be in a templated class but I don't want classes for each primitive type like int, float, etc. Is my usage above possible in C++?
I remember now. The trick was to use a base class that isn't templated and then make a child class that is templated and use the base class in the container to store it and templated functions to handle it.
#include <string>
#include <map>
using namespace std;
class Prop
{
public:
virtual ~Prop()
{
}
};
template<typename T>
class Property : public Prop
{
private:
T data;
public:
virtual ~Property()
{
}
Property(T d)
{
data = d;
}
T GetValue()
{
return data;
}
};
class Properties
{
private:
map<string, Prop*> props;
public:
~Properties()
{
map<string, Prop*>::iterator iter;
for(iter = props.begin(); iter != props.end(); ++iter)
delete (*iter).second;
props.clear();
}
template<typename T>
void Add(string name, T data)
{
props[name] = new Property<T>(data);
}
template<typename T>
T Get(string name)
{
Property<T>* p = (Property<T>*)props[name];
return p->GetValue();
}
};
int main()
{
Properties p;
p.Add<int>("age", 10);
int age = p.Get<int>("age");
return 0;
}
I think either boost::any or boost::variant in combination with std::map will do what you want.

iso c++ forbids declaration of generic with no type

My native language is C#, so when I started using C++, I wanted to create the get/set sugar syntax for library consumers available in C#.
So I wrote...
template<typename T>
class GetProperty
{
private:
T (*get)();
public:
GetProperty(T (*get)())
{
this->get = get;
}
operator T()
{
return get();
}
template<typename S, typename T>
GetProperty<S> operator=(GetProperty<T> fool)
{
throw 0;
}
};
Then, to to use this, I wrote the code:
template<typename T>
class Vector
{
private:
struct LinkItem
{
public:
T* Item;
LinkItem* Next;
GetProperty<int> Length (&getLength);
LinkItem(T* Item = NULL, int length = 1, LinkItem* Next = NULL)
{
this->Item = Item;
this->length = length;
this->Next = Next;
}
LinkItem& operator =(LinkItem rhs)
{
this->Item = rhs.Item;
this->length = rhs.length;
this->Next = rhs.Next;
return *this;
}
private:
int length;
int getLength()
{
return length;
}
};
LinkItem* current;
.
.
.
};
However, the C/C++ addition on Netbeans (I believe this is the g++ compiler) claims I am instantiating GetProperty with no type.
According to a Google search, this happens if someone forgets a using statement, or to include a header, etc.
But int is a primitive, so this can't be.
What's going on?
You are constructing GetProperty object while declaring it in a struct. That is not allowed in C++. You have to move the construction to the constructor.
In addition to the fact that VC++ doesn't implement non-static data member initializers, you can't treat the member function getLength as an int (*)(). Its type is int (LinkItem::*)().
struct Foo {
int foo(void) {return 1;}
};
int main() {
int (*var)() = &Foo::foo; // Error
int (Foo::*var)() = &Foo::foo; // Okay
}
You probably shouldn't be trying to import a foreign idiom like this, but if you really want to you can try something like the following. (Though as Nicol Bolas points out, you also probably shouldn't be implementing your own linked list, or naming it 'vector'. If you're learning C++ just learn the C++ way before going and trying to reinvent things.)
#include <functional>
template<typename T>
class GetProperty
{
private:
std::function<int()> get;
public:
GetProperty(std::function<int()> get)
: get(get)
{}
operator T()
{
return get();
}
};
template<typename T>
class Vector
{
private:
struct LinkItem
{
public:
T* Item;
LinkItem* Next;
GetProperty<int> Length;
LinkItem(T* Item = NULL, int length = 1, LinkItem* Next = NULL)
: Length([this] { return this->getLength(); })
{
...