I have a problem in C++ where I have
One abstract base class with common members and pure virtual functions. This is A in the code below.
Multiple derived classes with different members and functions. This is B and C in the code below.
Multiple derived classes that implements the virtual functions and has no new members. This is do_stuff_1 and do_stuff_2 in the code below.
My solution so far is to mix templates and abstract classes. The goal is to hold a pointer to the abstract classes B orC and call do_stuff. My questions are
Is my solution a good one?
If not, are there better solutions?
If so, are there some pitfalls I should be aware of?
Here is my solution so far
#include <iostream>
#include <memory>
/* base virtual class */
class A {
public:
int a;
A(int a) : a(a) {}
virtual void do_stuff() = 0;
};
/* concrete implementations of do_stuf */
template<class T>
class do_stuff_1 : public T {
public:
using T::T;
void do_stuff(){
std::cout << "do_stuff_1 " << this->a << std::endl;
}
};
template<class T>
class do_stuff_2 : public T {
public:
using T::T;
void do_stuff(){
std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
}
};
/* derived classes from A */
class B : public A {
public:
int b; // one member here but many more in my application
B(int a, int b): A(a), b(b) {}
};
class C : public A {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): A(a), c(c) {}
};
int main() {
std::unique_ptr<B> x;
x.reset(new do_stuff_1<B>(1, 1));
x->do_stuff();
std::cout << x->b << std::endl;
x.reset(new do_stuff_2<B>(1, 2));
x->do_stuff();
std::cout << x->b << std::endl;
std::unique_ptr<C> z;
z.reset(new do_stuff_1<C>(1, "Yo"));
z->do_stuff();
std::cout << z->c << std::endl;
z.reset(new do_stuff_2<C>(1, "Hello"));
z->do_stuff();
std::cout << z->c << std::endl;
return 0;
}
The result is
do_stuff_1 1
1
do_stuff_2 2
2
do_stuff_1 1
Yo
do_stuff_2 2
Hello
Your solution seems fine. It's a compile time approach and you create 4 different objects.
The main drawbacks are:
you won't know if the do_stuff() code is correct unless you instantiate the template.
you could instantiate do_stuff_1 or do_stuff_2 with classes which are not of base class A. You should at least use override in the template to make sure it overrides a virtual function.
Here a small improvement to address these issues:
template<class T>
class do_stuff_2 : public T {
public:
using T::T;
void do_stuff() override {
static_assert (std::is_base_of<A, T>::value, "T should be derived from A");
std::cout << "do_stuff_2 " << this->a + 1 << std::endl;
}
};
By the way, using make_unique would be nice.
To me looks like some kind of policy, this may look like:
#include <iostream>
#include <memory>
#include <type_traits>
struct AwayToDoTheStuff {
virtual void operator()(int a) = 0;
virtual ~AwayToDoTheStuff() {}
};
/* concrete implementations of do_stuf */
class HowToDoStuff1 : public AwayToDoTheStuff {
public:
void operator()(int a) override {
std::cout << "do_stuff_1 " << a << std::endl;
}
};
class HowToDoStuff2 : public AwayToDoTheStuff {
public:
void operator()(int a) override {
std::cout << "do_stuff_2 " << a + 1 << std::endl;
}
};
/* base virtual class */
template <class HowToDoStuff>
class A {
public:
int a;
A(int a) : a(a) {}
void do_stuff() {
static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
HowToDoStuff()(a);
}
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public A<HowToDoStuff> {
public:
int b; // one member here but many more in my application
B(int a, int b): A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public A<HowToDoStuff> {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): A<HowToDoStuff>(a), c(c) {}
};
int main() {
B<HowToDoStuff1>(1, 1).do_stuff();
B<HowToDoStuff2>(1, 2).do_stuff();
C<HowToDoStuff1>(1, "Yo").do_stuff();
C<HowToDoStuff2>(1, "Hello").do_stuff();
return 0;
}
but I must say this is quite hard to tell if a solution match well with an example that much generic. I hope it will help you in some ways...
EDIT:
You seem to need to have a common base class so that you can pass your objects B and C to a common function of the kind void f(A &a);
Then my example can be adapted that way:
/* base virtual class */
class A {
public:
void do_stuff() = 0;
};
template <class HowToDoStuff>
class Policy_A : public A {
public:
int a;
A(int a) : a(a) {}
void do_stuff() override {
static_assert(std::is_base_of<AwayToDoTheStuff, HowToDoStuff>::value);
HowToDoStuff()(a);
}
};
/* derived classes from A */
template <class HowToDoStuff>
class B : public Policy_A<HowToDoStuff> {
public:
int b; // one member here but many more in my application
B(int a, int b): Policy_A<HowToDoStuff>(a), b(b) {}
};
template <class HowToDoStuff>
class C : public Policy_A<HowToDoStuff> {
public:
std::string c; // one member here but many more in my application
C(int a, std::string c): Policy_A<HowToDoStuff>(a), c(c) {}
};
So that the do_stuff can be called on opaque A objects.
You may also pass the HowToDoStuff object at creation:
/* base virtual class */
class A {
std::unique_ptr<AwayToDoTheStuff> _stuffer;
public:
int a;
A(std::unique_ptr<AwayToDoTheStuff> stuffer, int a) : _stuffer(std::move(stuffer)), a(a) {}
void do_stuff() {
(*_stuffer)(a);
}
};
/* derived classes from A */
class B : public A {
public:
int b; // one member here but many more in my application
B(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, int b): A(std::move(stuffer), a), b(b) {}
};
class C : public A {
public:
std::string c; // one member here but many more in my application
C(std::unique_ptr<AwayToDoTheStuff> &stuffer, int a, std::string c): A(std::move(stuffer), a), c(c) {}
};
int main() {
auto stuffer1forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
auto stuffer2forB = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
B(stuffer1forB, 1, 1).do_stuff();
B(stuffer2forB, 1, 2).do_stuff();
auto stuffer1forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff1);
auto stuffer2forC = std::unique_ptr<AwayToDoTheStuff>(new HowToDoStuff2);
C(stuffer1forC, 1, "Yo").do_stuff();
C(stuffer2forC, 1, "Hello").do_stuff();
return 0;
}
Related
In the following, I expected class Child's protected field member _AorB to be of type B, and not A, but reality shows otherwise.
What am I mis-understanding, and how can I adjust the code for the desired behavior?
class A{
public:
void doit(){
std::cout<<" this is A!"<<std::endl;
}
};
class B{
public:
void doit(){
std::cout<<" this is B!"<<std::endl;
}
};
class Parent{
public:
void doit(){
_AorB.doit();
}
protected:
A _AorB;
};
class Child: public virtual Parent{
protected:
B _AorB;
};
int main()
{
cout<<"Hello World";
auto c = Child();
c.doit(); // I expected this to print "This is B" because c is Child(), and Child class's _AorB is of type B.
return 0;
}
You can make such changes:
template <typename AorB>
class Parent{
public:
void doit(){
_AorB.doit();
}
protected:
AorB _AorB;
};
class Child: public virtual Parent<B> {
}
Also take a look at What are the rules about using an underscore in a C++ identifier?
Reserved in any scope, including for use as implementation macros:
identifiers beginning with an underscore followed immediately by an uppercase letter
273K's answer is excellent.
Depending on what kind of problem you are trying to solve and how the data is held in the hierarchy, you could use a std::variant<A, B> to allow "flippy" behavior based on the type, and access that member variable through a virtual getter member function.
#include <iostream>
#include <variant>
class A {
public:
void doit() {
std::cout << " this is A!\n";
}
};
class B {
public:
void doit() {
std::cout << " this is B!\n";
}
};
class Parent {
public:
virtual ~Parent() = default;
void doit() {
auto ab = get_AorB();
std::visit([](auto arg) { arg.doit(); }, ab);
}
virtual auto get_AorB() -> std::variant<A, B> {
return _a;
}
protected:
A _a;
};
class Child : public virtual Parent {
protected:
B _b;
auto get_AorB() -> std::variant<A, B> override {
return _b;
}
};
int main() {
std::cout << "Hello World";
auto c = Child();
c.doit(); // "this is B!"
}
I have several disparate templated pure abstract classes. I derive from these to get a bunch of classes, and from there, I can use those to make a bunch of objects. I would like to put all of these objects into a container. However, they are all of different types. I am wondering how to accomplish this late-stage polymorphism.
Say this is my pre-existing code that I have right now:
#include <iostream>
template<typename T>
class A{
public:
A() : m_num(1.0) {};
virtual ~A() {};
virtual void printNum() const = 0;
protected:
T m_num;
};
template<typename T>
class B{
public:
B() : m_num(2.0) {};
virtual ~B() {};
virtual void printTwiceNum() const = 0;
protected:
T m_num;
};
class A_example : public A<int>
{
public:
A_example() : A<int>() {};
void printNum() const { std::cout << m_num << "\n"; };
};
class B_example : public B<int>
{
public:
B_example() : B<int>() {};
void printTwiceNum() const { std::cout << 2*m_num << "\n"; };
};
int main(){
A_example first;
B_example second;
first.printNum();
second.printTwiceNum();
return 0;
}
With more classes, it could get pretty messy inside of main(). Ideally I could jut iterate over the container and call print() on each element. My first thought is to use a std::vector<unique_ptr<Base>>. This seems to work:
#include <iostream>
#include <vector> // new include
#include <memory> // new include
#include <utility> // new include
// new Base class here
class Base{
public:
virtual ~Base(){};
};
template<typename T>
class A : public Base{ // new inheritance here
public:
A() : m_num(1.0) {};
virtual ~A() {};
virtual void printNum() const = 0;
protected:
T m_num;
};
template<typename T>
class B : public Base{ // new inheritance here as well
public:
B() : m_num(2.0) {};
virtual ~B() {};
virtual void printTwiceNum() const = 0;
protected:
T m_num;
};
class A_example : public A<int>
{
public:
A_example() : A<int>() {};
void printNum() const { std::cout << m_num << "\n"; };
};
class B_example : public B<int>
{
public:
B_example() : B<int>() {};
void printTwiceNum() const { std::cout << 2*m_num << "\n"; };
};
int main(){
std::vector<std::unique_ptr<Base>> v;
v.emplace_back( new A_example() );
v.emplace_back( new B_example() );
//v[0]->printNum(); // nope
//v[1]->printTwiceNum(); // nope
return 0;
}
This is cool because I didn't have to change A_example or B_example, and all I changed in A and B was that I added : public Base. However, I have no idea how to call each elements print*** function. Is there any way to call the printNum() and printTwiceNum() functions, and for them to be automatically recognized?
The simplest approach is to just make a virtual function Base::print and have your derived classes implement it. But that's not always appropriate.
Another approach is to branch on dynamic_cast conversions. The premise there is that some functions are only available on some classes. But this can get hairy especially when using class templates, as you must handle all expected template parameters.
To generalize this, you can use interface classes. Let's say you have lots of different classes but only a small number of print variations. In that case, it may make sense to do this:
class PrintNumInterface {
public:
virtual void printNum() const = 0;
};
class PrintTwiceNumInterface {
public:
virtual void printTwiceNum() const = 0;
};
template<typename T> class A : public Base, public PrintNumInterface { ... };
template<typename T> class B : public Base, public PrintTwiceNumInterface { ... };
And now, no matter how many additional classes or template expansions you have to deal with, you only need to handle these interfaces:
for (auto& p : v)
{
if (PrintNumInterface* iface = dynamic_cast<PrintNumInterface*>(p.get())
iface->printNum();
else if (PrintTwiceNumInterface* iface = dynamic_cast<PrintTwiceNumInterface*>(p.get())
iface->printTwiceNum();
}
How to do multiple inheritance just for function?
must share data of the base class
no virtual function (assume that vtable is expensive)
avoid virtual inheritance
implementation must be able to reside in .cpp
c++14 is allowed
Here are similar questions :-
Multiple inheritance in diamond shape with functions only - use virtual inheritance. Virtual inheritance is generally bad and expensive.
multiple inheritance without virtual inheritance - focuses on syntax and compiling rather than programming technique.
Multilevel inheritance in c++ (CRTP) , CRTP and multilevel inheritance , Eliminate redundancy with CRTP and multiple inheritance (C++03) and Using CRTP with virtual inheritance - implementation must be in header
Here is a sample code (coliru demo) :-
class O{
protected: int database=0;
};
class A : public O{
public: void print(){
std::cout<<database<<std::endl;
}
};
class B : public O{
public: void set(int s){
database=s+1;
}
};
class AB : public O{
public: void print(){//duplicate
std::cout<<database<<std::endl;
}
public: void set(int s){//duplicate
database=s+1;
}
};
//AB ab; ab.set(1); ab.print(); // would print 2
Here is my attempt (wandbox demo). I abuse CRTP :( :-
class O{
public: int database=0;
};
template<class T>class OA{
public: void print(){
std::cout<<static_cast<T*>(this)->database<<std::endl;
}
};
template<class T>class OB{
public: void set(int s){
static_cast<T*>(this)->database=s+1;
}
};
class A :public O,public OA<A>{};
class B :public O,public OB<B>{};
class AB :public O,public OA<AB>,public OB<AB>{};
It works, but it looks inelegant.
Furthermore, implementation must be in header (because OA and OB are template classes).
Are there better approaches? Or is this the way to go?
Sorry if it is too newbie question or already asked. I am a C++ beginner.
Edit
Give extended example of using please.
In ECS, it would be useful in some cases :-
class O{
protected: EntityHandle e;
};
class ViewAsPhysic : public O{ //A
public: void setTransform(Transformation t){
Ptr<PhysicTransformComponent> g=e;
g->transform=t;
}
};
class ViewAsLight : public O{ //B
public: void setBrightness(int t){
Ptr<LightComponent> g=e;
g->clan=t;
}
};
class ViewAsLightBlock : public O{ //AB
//both functions
};
The problem here is that the database field is member of class O. So without virtual inheritance, A and B will have each their own copy of database. So you must find a way to force A and B to share same value. You could for example use a reference field initialized in a protected constructor:
#include <iostream>
class O{
int _db;
protected: int &database;
O(): database(_db) {};
O(int &db): database(db) {};
};
class A : public O{
public: void print(){
std::cout<<database<<std::endl;
}
A() {} // public default ctor
protected: A(int& db): O(db) {}; // protectect ctor
};
class B : public O{
public: void set(int s){
database=s+1;
}
B() {} // public default ctor
protected: B(int& db): O(db) {}; // protectect ctor
};
class AB : public A, public B {
int _db2;
public: AB(): A(_db2), B(_db2) {}; // initialize both references to same private var
};
int main() {
AB ab;
ab.set(1);
ab.print();
return 0;
}
displays as expected:
2
Above code uses no virtual inheritance, no virtual function and no templates, so method can safely implemented in cpp files. The class AB actually uses methods from its both parents and has still a coherent view on its underlying data. In fact it simulates an explicit virtual inheritance by building the common data in the most derived class and injecting in through protected constructors in its parents.
Something like this?
must share data of the base class - check
no virtual function (assume that vtable is expensive) - check
avoid virtual inheritance - check
implementation must be able to reside in .cpp- check
c++14 is allowed - check. c++11 used.
#include <iostream>
class O {
protected:
int database = 0;
};
/*
* the concept of implementing print for a base class
*/
template<class...Bases>
struct implements_print : Bases... {
void print() const {
std::cout << this->database << std::endl;
}
};
/*
* The concept of implementing set for a base class
*/
template<class...Bases>
struct implements_set : Bases... {
void set() {
++this->database;
}
};
struct B : implements_set<O> {
};
struct A : implements_print<O> {
};
struct AB : implements_set<implements_print<O>> {
};
int main() {
A a;
a.print();
B b;
b.set();
AB ab;
ab.set();
ab.print();
}
Another way, using composition and an access class to provide access to the protected member. This example shows how to defer the work on database to another compilation unit:
#include <iostream>
/*
* this stuff in cpp
*/
namespace implementation
{
void print(const int& database) {
std::cout << database << std::endl;
}
void set(int& database) {
++database;
}
}
/*
* this stuff in header
*/
struct OAccess;
class O {
private:
int database = 0;
friend OAccess;
};
struct OAccess {
template<class Host>
constexpr decltype(auto) database(Host &host) const { return (host.database); } // note: () makes reference
template<class Host>
constexpr decltype(auto) database(Host const &host) const { return (host.database); } // note: () makes reference
};
/*
* the concept of implementing print for a derived class
*/
template<class Host>
struct implements_print {
void print() const {
OAccess access;
implementation::print(access.database(self()));
}
private:
decltype(auto) self() const { return static_cast<Host const &>(*this); }
};
/*
* The concept of implementing set for a derived class
*/
template<class Host>
struct implements_set {
void set() {
OAccess access;
implementation::set(access.database(self()));
}
private:
decltype(auto) self() { return static_cast<Host &>(*this); }
};
template<template<class> class...Impls>
struct OImpl : Impls<OImpl<Impls...>> ..., O {
};
using B = OImpl<implements_set>;
using A = OImpl<implements_print>;
using AB = OImpl<implements_print, implements_set>;
int main() {
A a;
a.print();
B b;
b.set();
AB ab;
ab.set();
ab.print();
}
We start with defining the concepts of things that can print and things that can be set:
namespace util {
template<class Base, class Derived, class R=void>
using if_base = std::enable_if_t< std::is_base_of< std::decay_t<Base>, std::decay_t<Derived>>::value, R >;
struct stub {};
}
namespace concepts {
template<class Token>
void do_print(Token, util::stub const&)=delete;
template<class Token>
void do_set(Token, util::stub&, int)=delete;
struct has_print {
struct token { friend struct has_print; private: token(int){} };
template<class T>
friend util::if_base<has_print, T> print(T const& t) {
do_print(get_token(), t);
}
private: static token get_token() { return 0; }
};
struct has_set {
struct token { friend struct has_set; private: token(int){} };
template<class T>
friend util::if_base<has_set, T> set(T& t, int x) {
do_set(get_token(),t, x);
}
private: static token get_token() { return 0; }
};
}
We then declare O and the operations you can support on it:
namespace DB {
class O;
void do_print(::concepts::has_print::token, O const& o);
void do_set(::concepts::has_set::token, O& o, int);
class O{
protected: int database=0;
friend void do_print(::concepts::has_print::token, O const&);
friend void do_set(::concepts::has_set::token, O&, int);
};
class A : public O, public concepts::has_print {
};
class B : public O, public concepts::has_set {
};
class AB : public O, public concepts::has_print, concepts::has_set {
};
}
void DB::do_print(::concepts::has_print::token, O const& o ) { std::cout << o.database << std::endl; }
void DB::do_set(::concepts::has_set::token, O& o, int x) { o.database = x+1; }
The hard part of this is the access control.
I ensure it isn't possible to call do_set except through has_set::set.
That is what all those tokens are about. You can strip them out and their overhead if you are willing to just say "don't call the do_ functions" (and maybe give them another name, like private_impl_set).
Live example.
To start discussion.
class O
{
// no virtual destructor. So cant use polymorphic deletion
// like :
// O *o = new AB;
// delete o;
protected: int database=0;
};
class A : virtual public O{
public: void print(){
std::cout<<database<<std::endl;
}
};
class B : virtual public O{
public: void set(int s){
database=s+1;
}
};
class AB : protected A, protected B{}; // no vtable
void foo() {
AB ab;
ab.print(); // won't perform virtual call.
}
Let's say I have two classes, A and B:
class B;
class A
{
private:
int an_int;
B *something_else;
public:
A(int n) : an_int(n), something_else(nullptr) {}
};
class B
{
private:
int an_int;
A *something_else;
public:
B(int n) : an_int(n), something_else(nullptr) {}
};
How can I make it so that I don't have to prototype B in order to have a pointer to a B object in class A?
This solution is most probably what is intended in an exercise about inheritance where you can't use a forward declaration.
Instead of the forward declaration
class B;
you can define an interface like
struct I_whoop
{
virtual void whoop_whoop() = 0;
};
then let class B implement that interface, and just use a pointer to the interface.
Actually You can not if using concrete class.
But You can achieve your goal by using template parameters. Making class B a template parameter of template class A.
How can I make it so that I don't have to prototype B in order to have a pointer to a B object in class A?
Like this:
class A
{
private:
int an_int;
class B *something_else;
public:
A(int n) : an_int(n), something_else(nullptr) {}
};
class B
{
private:
int an_int;
class A *something_else;
public:
B(int n) : an_int(n), something_else(nullptr) {}
};
In C and C++ it has never been necessary for a type T to be
forward declared before the declaration of objects of type T *
(or const variants), because the declaration of a T * per se requires
the compiler only to know the size of a T *, not the size or definition
of a T, and the size of a T * is the same, regardless of T.
Here is a more fleshed-out illustration:
class A
{
private:
int an_int;
class B *something_else;
public:
A(int n, class B * pb = nullptr) : an_int(n), something_else(pb) {}
int get_int() const {
return an_int;
}
void set_B(class B * pb) {
something_else = pb;
}
class B * get_B() const {
return something_else;
}
};
class B
{
private:
int an_int;
class A *something_else;
public:
B(int n, class A * pa = nullptr) : an_int(n), something_else(pa) {}
int get_int() const {
return an_int;
}
void set_A(class A * pa) {
something_else = pa;
}
class A * get_A() const {
return something_else;
}
};
#include <iostream>
int main()
{
A a(1);
B b(2);
a.set_B(&b);
b.set_A(&a);
std::cout << a.get_B()->get_int() << std::endl;
std::cout << b.get_A()->get_int() << std::endl;
return 0;
}
Output:
2
1
(gcc 4.9.2/clang 3.5.2 -std=c++11 -Wall -pedantic)
I have the following code :
class A{};
class B: public A{};
class C: public A{};
class MyVisitor
{
public:
void visit(B*);
void visit(C*);
};
And then collection of A* objects, I want to achieve the following :
1)
MyVisitor visitor;
for(vector<A*>::iterator it = vec.begin(); it!= vec.end();it++)
visitor->visit(a);
2) Somehow determine at compile time, if A* points to derived object D,and give compiler error, if MyVisitor::visit(D*) function is not present
I know that 1) is achievable with some multimethods implementation, I guess I can find some implementations of multimethods for c++ . But is 2) somehow possible ?
You could use dynamic_cast like this (inside the body of your for loop) since the behavior should vary at run-time (according to the actual type of data).
ClassB* ba = dynamic_cast<ClassB*>(a);
if (ba)
visitor->visit(ba);
ClassC* ca = dynamic_cast<ClassC*>(a);
if (ca)
visitor->visit(ca);
Maybe your visit functions might be declared virtual (for your ClassD thing).
Otherwise organize your classes as a tree (not a forest) of classes, and have your topmost root class
class Topmost {
virtual int classnum() const;
and adopt the convention that each non-abstract class gives its unique classnum etc... Or have a metaclass mechanism (like e.g. Qt has)
You can try something like this.
#include <iostream>
class A
{
virtual void visit() = 0;
};
class B: private A
{
public:
void visit()
{
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
class C: private A
{
public:
void visit()
{
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
template <typename... Args>
class MyVisitor : public Args...
{
public:
template <typename T>
void visit(T* t)
{
t->visit();
}
};
int main()
{
MyVisitor<B, C> visitor;
B b;
B* bp = &b;
visitor.visit(bp);
return 0;
}
Live example
You may apply the visitor pattern completly:
class B;
class C;
class IVisitor
{
public:
void visit(B&) = 0;
void visit(C&) = 0;
};
class A
{
virtual ~A() = default;
virtual void accept(IVisitor& v) = 0;
};
class B: public A{ void accept(IVisitor& v) override { v.visit(*this); } };
class C: public A{ void accept(IVisitor& v) override { v.visit(*this); } };