I'm having a problem with abstract/virtual classes, a replication of the problem here:
#include <iostream>
class A
{
protected:
virtual std::string getDateTime() = 0;
virtual void Write(std::string data, bool addDate) = 0;
virtual bool CheckFile() = 0;
virtual bool OpenFile(std::string path) = 0;
virtual void CloseFile() = 0;
};
class B
: public A
{
public:
virtual std::string ToString() { return ""; };
virtual void Write(std::string data) { };
};
class C
: public A
{
protected:
std::string getDateTime()
{
return "TODAY";
};
void Write(std::string data, bool addDate)
{
std::cout << "BasicClassA Write" << std::endl;
};
bool CheckFile()
{
std::cout << "BasicClassA CheckFile" << std::endl;
return true;
};
bool OpenFile(std::string path)
{
std::cout << "BasicClassA OpenFile" << std::endl;
return true;
};
void CloseFile()
{
std::cout << "BasicClassA CloseFile" << std::endl;
};
};
class D
: public B,
public C
{
public:
BasicClassB();
virtual ~BasicClassB();
std::string ToString()
{
return "BasicClassB tostring";
};
void Write(std::string data)
{
std::cout << "BasicClassB Write" << std::endl;
};
};
int main(int ac, char *av[])
{
BasicClassB b;
std::cout << b.ToString() << std::endl;
b.Write("");
return 0;
}
This has a compile error:
../src/main.cpp: In function ‘int main(int, char**)’:
../src/main.cpp:82: error: cannot declare variable ‘b’ to be of abstract type ‘BasicClassB’
../src/main.cpp:64: note: because the following virtual functions are pure within ‘BasicClassB’:
../src/main.cpp:13: note: virtual std::string BaseClassA::getDateTime()
../src/main.cpp:14: note: virtual void BaseClassA::Write(std::string, bool)
../src/main.cpp:15: note: virtual bool BaseClassA::CheckFile()
../src/main.cpp:16: note: virtual bool BaseClassA::OpenFile(std::string)
../src/main.cpp:17: note: virtual void BaseClassA::CloseFile()
Perhaps I'm missing the point here, but the implementation of BaseClassA (being BasicClassA) should contain these functions, and since BasicClassB is subclassed from BasicClassA as well, it should also contain these functions?
What am I missing? What should I do to make this compile?
[edit]
I updated the class names as suggested by the comment
For clarification: I used pure virtual in the class A to force any of the children to implement the functions.
It seems virtual inheritance is what I need, however, I don't seem to get the correct way on how to do this in my case...
The goal is to have several "base" classes, kind of like interfaces, forcing the children to implement the functions, but any children of those should inherit the overriden function (just like virtual inheritance)
However, using any combination of
class Any : public virtual Anyother { }
doesn't work out and always gives the same compile error (the one above). Perhaps I need to change more than just the virtual in the inheritance?
It doesn't work that way by default in C++ - You want a diamond inheritance pattern, but in C++ you get separate roots: So BasicClassA and BaseClassB each have their own BaseClassA (vtable and instance variables).
You probably want to use Virtual Inheritance.
For a clearer idea on non-virtual inheritance:
#include <iostream>
class A
{
public:
A(int x) {m_a = x;}
virtual ~A() {}
int m_a;
virtual int getA() {return m_a;}
};
class B : public A
{
public:
B() : A(1) {}
};
class C : public A
{
public:
C() : A(2) {}
};
class D : public B,
public C
{
};
void useB(B* b)
{
std::cout << "useB:" << b->getA() << std::endl;
}
void useC(C* c)
{
std::cout << "useC:" << c->getA() << std::endl;
}
int main()
{
D* d = new D();
useB(d);
useC(d);
return 0;
}
This produces the output:
useB:1
useC:2
This example shows virtual inheritance, and the kind of mix-in behaviour you want.
#include <iostream>
class A
{
public:
A(int x) {m_a = x;}
virtual ~A() {}
int m_a;
virtual int getA() {return m_a;}
virtual int virt() = 0;
};
class B : virtual public A
{
public:
B() : A(1) {}
};
class C : virtual public A
{
public:
C() : A(2) {}
virtual int virt() {return 42;}
};
class D : public B,
public C
{
public:
D() : A(3) {}
};
void useB(B* b)
{
std::cout << "useB:" << b->getA() << std::endl;
}
void useC(C* c)
{
std::cout << "useC:" << c->getA() << std::endl;
std::cout << "useC-virt:" << c->virt() << std::endl;
}
int main()
{
D* d = new D();
useB(d);
useC(d);
return 0;
}
Output:
useB:3
useC:3
useC-virt:42
Note: The constructors from C and B don't get a say in setting m_a, which is controller by the D() constructor initialisation list.
EDIT:
Applying virtual to your code:
#include <iostream>
class A
{
protected:
virtual std::string getDateTime() = 0;
virtual void Write(std::string data, bool addDate) = 0;
virtual bool CheckFile() = 0;
virtual bool OpenFile(std::string path) = 0;
virtual void CloseFile() = 0;
};
class B
: virtual public A
{
public:
virtual std::string ToString() { return ""; };
virtual void Write(std::string data) { };
};
class C
: virtual public A
{
protected:
std::string getDateTime()
{
return "TODAY";
};
void Write(std::string data, bool addDate)
{
std::cout << "C Write" << std::endl;
};
bool CheckFile()
{
std::cout << "C CheckFile" << std::endl;
return true;
};
bool OpenFile(std::string path)
{
std::cout << "C OpenFile" << std::endl;
return true;
};
void CloseFile()
{
std::cout << "C CloseFile" << std::endl;
};
};
class D
: public B,
public C
{
public:
std::string ToString()
{
return "D tostring";
};
void Write(std::string data)
{
std::cout << "D Write" << std::endl;
};
};
int main(int ac, char *av[])
{
D b;
std::cout << b.ToString() << std::endl;
b.Write("");
return 0;
}
BaseClassA has 5 pure virtual functions. A class with even one pure virtual function is an "Abstract class". The purpose of pure virtual functions (in short) is to disallow creation of objects of the abstract class.
In order to instantiate BaseClassB, it needs to have definitions of all 5 functions which you declared pure virtual in BaseClassA. (In absence of these definitions, BaseClassB also becomes Abstract and hence you cannot create objects from it).
BasicClassB only derives from BaseClassA which is an abstract class since those methods :
virtual std::string getDateTime() = 0;
virtual void Write(std::string data, bool addDate) = 0;
virtual bool CheckFile() = 0;
virtual bool OpenFile(std::string path) = 0;
virtual void CloseFile() = 0;
Are pure virtual.
The error message is pretty clear: to be able to instantiate a BasicClassB you must provide an implementation for the forementioned methods.
Also, note that your definition of Write in BasicClassB:
virtual void Write(std::string data) { };
Differs from the one in BaseClassA:
virtual void Write(std::string data, bool addDate) = 0;
So this method still needs to be implemented for BasicClassB to become instantiable.
The fact that you add "=0" to your functions means that they are purely virtual, and must be implemented in child classes. Which is obviously not what you want. If you drop the "=0" from the functions that have an implementation in the base class, it should be working as intended.
Related
I have two variants of the same method. I also have an instance of a base class type, but I don't know what specific class it is an instance of. I now want to automatically select the appropriate method depending on the actual type of the object. It seems impossible though and the only solution I can come up with is to check all possibilities by casting.
There has to be a nicer solution though.
Here is my minimal example:
// Example program
#include <iostream>
#include <string>
#include <memory>
class A
{
public:
virtual void bar() const = 0;
};
class B : public A
{
public:
void bar() const
{
std::cout << "B.bar()" << std::endl;
}
};
class C : public A
{
public:
void bar() const
{
std::cout << "C.bar()" << std::endl;
}
};
class Z
{
public:
Z(int variable) : m_variable(variable) {};
void foo(std::shared_ptr<B> b)
{
std::cout << "Calling foo(B) method! " << m_variable << std::endl;
b->bar();
}
void foo(std::shared_ptr<C> c)
{
std::cout << "Calling foo(C) method!" << m_variable << std::endl;
c->bar();
}
private:
int m_variable;
};
int main()
{
std::shared_ptr<A> b(new B());
Z z(42);
//z.foo(b); // This doesn't work
// But this does
std::shared_ptr<B> b_cast = std::dynamic_pointer_cast<B>(b);
if (b_cast.get())
z.foo(b_cast);
}
http://cpp.sh/9fqne
At the moment I have to resort to dynamic_pointer_cast, but I find it kinda ugly and not very maintainable.
I also don't want to add the functionality of foo() to the classes B and C, because those are small independent data structures on which many other classes operate.
Thank you very much!
EDIT: In the original post I simplified a bit too much. The new example should clear things up.
Add a pure virtual function foo() to your base class and override in subsequent derived classes. Then have your global function foo() (which has nothing to do with member functions with the same name) accept a reference to std::shared_ptr const as a parameter:
#include <iostream>
#include <memory>
class A{
public:
virtual void foo() = 0;
};
class B : public A{
public:
void foo() override{
std::cout << "Calling foo(B) method!" << std::endl;
}
};
class C : public A{
public:
void foo() override{
std::cout << "Calling foo(C) method!" << std::endl;
}
};
void foo(const std::shared_ptr<A>& param){
param->foo();
}
int main(){
std::shared_ptr<A> b = std::make_shared<B>();
std::shared_ptr<A> c = std::make_shared<C>();
foo(b);
foo(c);
}
As BoBTFish pointed out, the visitor pattern is a potential solution for this problem:
// Example program
#include <iostream>
#include <string>
#include <memory>
class B;
class C;
class Visitor
{
public:
virtual void visit(B* b) const = 0;
virtual void visit(C* b) const = 0;
};
class A
{
public:
virtual void bar() const = 0;
virtual void accept(const Visitor* visitor) = 0;
};
class B : public A
{
public:
void bar() const
{
std::cout << "B.bar()" << std::endl;
}
void accept(const Visitor* visitor)
{
visitor->visit(this);
}
};
class C : public A
{
public:
void bar() const
{
std::cout << "C.bar()" << std::endl;
}
void accept(const Visitor* visitor)
{
visitor->visit(this);
}
};
class Z : public Visitor
{
public:
Z(int variable) : m_variable(variable) {};
void visit(B* b) const
{
std::cout << "Calling foo(B) method! " << m_variable << std::endl;
b->bar();
}
void visit(C* c) const
{
std::cout << "Calling foo(C) method!" << m_variable << std::endl;
c->bar();
}
private:
int m_variable;
};
int main()
{
std::shared_ptr<A> b(new B());
Z z(42);
b->accept(&z);
}
http://cpp.sh/2vah5
Thank you very much!
The following code is a simplified version of a VisitorPattern I have implemented on my project.
#include <iostream>
class AVisitor {
public:
virtual void visit(class A *) = 0;
};
class ExtendedVisitor : public AVisitor {
public:
virtual void visit(class B *) = 0;
};
class A {
public:
virtual void accept(AVisitor *visitor) {
std::cout << "Call accept of A" << std::endl;
visitor->visit(this);
}
};
class B : public A {
public:
void accept(AVisitor *visitor) override {
std::cout << "Call accept of B" << std::endl;
B *just_this = this;
visitor->visit(just_this); //why this calls to visit(A*)
visitor->visit((B*) just_this); //useless casting
}
};
class ActualVisitor : public ExtendedVisitor {
public:
void visit(A *x) override {
std::cout << "Call visit on A*" << std::endl;
}
void visit(B *x) override {
std::cout << "Never called" << std::endl;
}
};
int main() {
ActualVisitor visitor;
A *a = new B();
a->accept(&visitor);
}
I don't understand why the accept method of class B calls to the visitor(A*) method instead of visitor(B*). The main function prints
Call accept of B
Call visit on A*
Call visit on A*
Instead, the following code behaves as I expected:
#include <iostream>
class AVisitor {
public:
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
};
class A {
public:
virtual void accept(AVisitor *visitor) {
std::cout << "Call accept of A" << std::endl;
visitor->visit(this);
}
};
class B : public A {
public:
void accept(AVisitor *visitor) override {
std::cout << "Call accept of B" << std::endl;
B *just_this = this;
visitor->visit(just_this); //now it works
visitor->visit((B*) just_this);
}
};
class ActualVisitor : public AVisitor {
public:
void visit(A *x) override {
std::cout << "Call visit on A*" << std::endl;
}
void visit(B *x) override {
std::cout << "Call visit on B*" << std::endl;
}
};
int main() {
ActualVisitor visitor;
A *a = new B();
a->accept(&visitor);
}
It now prints:
Call accept of B
Call visit on B*
Call visit on B*
The problem then seems to be the inheritance of the AVisitor class. I wonder why this happens and what is the proper way to design a VisitorPattern with "specialized" visitors (here ExtendedVisitor can also visit a B object)
Your B::accept has the following signature:
void accept(AVisitor *visitor) override;
So, let's check the interface of AVisitor. It has
virtual void visit(class A *) = 0;
and that is all it has (in your first version). It is true that ExtendedVisitor has
virtual void visit(class B *) = 0;
but that does not override the method in AVisitor. In fact, your second version can help you see why. Since
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
can reside together in the same class (they are overloads in your second version), then they are distinct methods in this respect.
You are implementing Visitor incorrectly. Here's the right way:
class AVisitor {
public:
virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;
// virtual void visit(class C *) = 0; etc
// a separate function for every class in your hierarchy
};
and then
class ActualVisitor : public Visitor ...
There's no need for ExtendedVisitor.
Yes AVisitor must know about every class in your hierarchy. This is the principal drawback of this pattern.
I have a sample interface that delegates behavior to the implementing class:
class IBase
{
public:
virtual void Do(IBase* base) = 0;
virtual std::string name() = 0;
};
I then have 1..N classes that implement IBase:
class A : public IBase
{
public:
virtual void Do(IBase* base);
virtual std::string name() { return "A"; }
};
class B : public IBase
{
public:
virtual void Do(IBase* base);
virtual std::string name() { return "B"; }
};
I then want the body of the Do() method to call free methods that are defined for everything that implements IBase:
void method(A* a, B* b)
{
std::cout << a->name() << " " << b->name() << std::endl;
}
void method(B* b, A* a)
{
method(b, a);
}
This doesn't compile because with this code because IBase cannot resolve to the derived type:
void Test::Run()
{
IBase* a = new A();
IBase* b = new B();
b->Do(a);
}
How do I make this work, or something similar? The free methods implement all possible combinations, and it seems like there is a trick to get the IBase* to be acceptable in one of the overloads.
Secondly, how do you implement a interface scheme where each implementer has a shared method that takes an interface? Perhaps this is better implemented with just free methods and removing the Do(IBase*) from the IBase interface.
Edit:
It works if (a) is declared to be type A. Whats the best way to make the code above work with the IBase?
void Test::Run()
{
A* a = new A();
IBase* b = new B();
b->Do(a);
}
Literal code I am compiling:
class IBase
{
public:
virtual void Do(IBase* base) = 0;
virtual std::string name() = 0;
};
class A : public IBase
{
public:
virtual void Do(IBase* base);
virtual std::string name();
};
class B : public IBase
{
public:
virtual void Do(IBase* base);
virtual std::string name();
};
class Test
{
public:
static void Run();
};
namespace
{
void method(A* a, B* b)
{
std::cout << a->name() << " " << b->name() << std::endl;
}
void method(B* b, A* a)
{
method(b, a);
}
}
void A::Do(IBase* base)
{
method(this, base);
}
std::string A::name()
{
return "A";
}
void B::Do(IBase* base)
{
method(this, base);
}
std::string B::name()
{
return "B";
}
void Test::Run()
{
IBase* a = new A();
IBase* b = new B();
b->Do(a);
}
Visual Studio 2013:
Error 1 error C2665: 'anonymous-namespace'::method' : none of the 2 overloads could convert all the argument types
Error 2 error C2665: 'anonymous-namespace'::method' : none of the 2 overloads could convert all the argument types
So if I understand you correctly, you want A::Do to look like this:
void A::Do(IBase* other) {
if other is A, then call:
method(this,other) for arguments A,A
else if other is B, then call
method(this,other) for arguments A,B
etc.
}
There are two answers to that. The best approach is usually to change the design. Make method a virtual function in IBase instead of a free function, and extract any functionality specific to A and B into yet another virtual function.
class IBase
{
public:
virtual void Do(IBase* base) = 0;
virtual std::string name() = 0;
virtual void method(IBase* other);
virtual void method2() = 0;
};
void IBase::method(IBase* other) {
std::cout << name() << " " << other->method2() << std::endl;
}
The other option is to use type casting:
void A::Do(IBase* other) {
if other is A, then call:
method(this,dynamic_cast<A*>(other)))
else if other is B, then call
method(this,dynamic_cast<B*>(other))
etc.
}
This approach usually does not scale well, is hard to maintain and error-prone.
Say I want to overload a function outside of my classes with different pointer types. Can I do this in C++11?
struct Bird;
struct Bear;
struct Animal {
virtual Bird* AsBird() = 0;
virtual Bear* AsBear() = 0;
};
struct Bird : public Animal{
virtual Bird* AsBird(){ return this; }
virtual Bear* AsBear(){ return NULL; }
};
struct Bear : public Animal{
virtual Bird* AsBird(){ return NULL; }
virtual Bear* AsBear(){ return this; }
};
void Print(Animal* a){
cout << "I don't know what animal this is!" << endl;
}
void Print(Bear* b){
cout << "That's a bear!" << endl;
}
void Print(Bird* b){
cout << "That's a bird!" << endl;
}
int main(int argc, char* argv[]){
Animal* a = new Bear;
Bear* bear;
Bird* bird;
if (bear = a->AsBear()){
Print(bear);
} else if (bird = a->AsBird()){
Print(bird);
}
return 0;
}
This code works, but it's absolutely awful. I have tried playing around with templates and auto, but the compiler doesn't want anything to do with my evil experiments. Is there a legitimate way of doing this?
What you did is overloading the Print free function by changing the type of its parameter, there is no inheritance involved, and this is perfectly legal.
But you don't need it (or any dynamic_cast-like as you did) : What you should do is add a virtual void Print() const = 0 in your Animal base class instead, and override it in each derived class.
Example:
struct Animal {
virtual void Print() const = 0;
};
struct Bird : public Animal{
void Print() const { cout << "That's a bird!\n"; }
};
struct Bear : public Animal{
void Print() const { cout << "That's a bear!\n"; }
};
int main(){
Animal* a = new Bear;
a->Print();
Animal* b = new Bird;
b->Print();
}
As quantdev noted, the traditional way is adding a virtual function to your class hierarchy.
However, if you don't want to do it, you can use dynamic_cast, which was invented specifically for purposes like this.
struct Animal {
virtual ~Animal() {} // base class must have a virtual method to use dynamic_cast
};
...
if (bear = dynamic_cast<Bear*>(a)){
Print(bear);
} else if (bird = dynamic_cast<Bird*>(a)){
Print(bird);
}
This is a little better than what you have: if you add another inheriting class, you don't have to change your base class; you must only change your main function and add a new printing function.
If this is still "awful", maybe you should make Print a virtual function.
This looks like a use case for the visitor pattern.
struct Bird;
struct Bear;
struct Visitor
{
virtual void Visit(Bird& x) = 0;
virtual void Visit(Bear& x) = 0;
};
struct PrintVisitor : Visitor
{
void Visit(Bird& x) override { cout << "That's a bird!" << endl; };
void Visit(Bear& x) override { cout << "That's a bear!" << endl; };
};
struct Animal
{
virtual void Accept(Visitor& v) = 0;
};
struct Bird : public Animal
{
void Accept(Visitor& v) override { v.Visit(*this); }
};
struct Bear : public Animal
{
void Accept(Visitor& v) override { v.Visit(*this); }
};
int main(int argc, char* argv[])
{
Bear bear;
Bird bird;
PrintVisitor visitor;
Animal* a = &bear;
a->Accept(visitor);
a = &bird;
a->Accept(visitor);
}
Of course, it might just be easier to make Print a virtual member function.
The AsBear, AsBird functions, you've simply reimplemented dynamic_cast.
As far as the overloads of Print goes, the simplest solution here is to make Print be a virtual function in the Animal hierarchy.
My recommended solution would be to use the visitor pattern. Since that's what it seems like you're trying to do by decoupling the Print function and the class hierarchy.
#include <iostream>
struct Bird;
struct Bear;
struct Animal {
struct Visitor {
virtual void operator()(const Bird *) const = 0;
virtual void operator()(const Bear *) const = 0;
};
virtual void Accept(const Visitor &visitor) const = 0;
};
struct Bird : public Animal {
virtual void Accept(const Visitor &visitor) const override {
visitor(this);
}
};
struct Bear : public Animal {
virtual void Accept(const Visitor &visitor) const override {
visitor(this);
}
};
struct Print : public Animal::Visitor {
virtual void operator()(const Bird *) const override {
std::cout << "Bird" << std::endl;
}
virtual void operator()(const Bear *) const override {
std::cout << "Bear" << std::endl;
}
};
int main() {
Bird bird;
Animal *animal = &bird;
animal->Accept(Print());
}
I need a base class that gives me primitive type of data's pointer. I add a function in it. I derived types of class. I used void * to support all primitive types as a return type but it is like old C days. It is not good for OOP. Does one have an suggestion to do in a proper way in OOP?
#include <iostream>
class base {
public:
virtual void *getPtr() = 0;
virtual ~base() {};
};
class derivedAType : public base {
protected:
int _i;
public:
derivedAType(int i): _i(0) { _i = i; };
virtual ~derivedAType() {}
virtual void *getPtr() {
return static_cast<void *>(&_i);
}
};
class derivedBType : public base {
protected:
short _s;
public:
derivedBType(short s): _s(0) { _s = s; };
virtual ~derivedBType() {}
virtual void *getPtr() {
return static_cast<void *>(&_s);
}
};
int main()
{
base *b1 = new derivedAType(1203912);
base *b2 = new derivedBType(25273);
std::cout << "b1 : " << *(static_cast<int *>(b1->getPtr()))
<< "\nb2 : " << *(static_cast<short *>(b2->getPtr()))
<< std::endl;
delete b2;
delete b1;
return 0;
}
Make the base class a template class with the data type as the template variable
template<typename DataType>
class base {
virtual DataType* getPtr() = 0;
//...
};
and
class derivedAType : public base<int>
But this changes base class to a template class which means you cant store them together, base<int> is different from base<short>
If this isnt acceptable, the other options is just a tad bit cleaner than your code but abt the same, refer to this question. Basically derived class return types can reflect their true type and i think it should get automatically converted to void*, so you dont have to manually cast the pointer.
Not sure about your problem. But maybe a double callback can help:
class Callback {
public:
virtual void do_int( int i ) const = 0;
virtual void do_short( short s ) const = 0;
/* ... */
}
class base {
public:
virtual void do_stuff(const Callback & c); /* will need a more telling name */
virtual ~base() {};
};
class derivedAType : public base {
protected:
int _i;
public:
derivedAType(int i): _i(0) { _i = i; };
virtual ~derivedAType() {}
virtual void do_stuff(const Callback & c) {
c.do_int( _i );
}
};
class derivedBType : public base {
protected:
short _s;
public:
derivedBType(short s): _s(0) { _s = s; };
virtual ~derivedBType() {}
virtual void do_stuff( const Callback & c) {
c.do_short( _s );
}
};
class print_callback : public Callback {
public:
virtual void do_int( int i ) const { std::cout << i; }
virtual void do_short( short s ) const { std::cout << s; }
}
int main() {
base *b1 = new derivedAType(1203912);
base *b2 = new derivedBType(25273);
std::cout << "b1 : ";
b1->do_stuff(print_callback());
std::cout << "\nb2 : ";
b2->do_stuff(print_callback());
std::cout << std::endl;
delete b2;
delete b1;
return 0;
}
Of course you can simplify this by just storing the created print callback, and using it twice.