I am pretty new to C++. Today, I am experiencing some issues in mixing nested classes and interfaces.
I wrote a small (useless) program that will be more effective at explaining my issue than long sentences:
#include <iostream>
#include <vector>
class SomeInterface {
public:
virtual int SomeMethod() = 0;
class reference {
public:
virtual operator int() const = 0;
virtual reference& operator=(int x) = 0;
};
virtual reference operator[](unsigned int pos) = 0;
};
class A : public SomeInterface {
public:
A(unsigned int size) { vec_.resize(size, 0); }
int SomeMethod() { return 1; }
class reference : public SomeInterface::reference {
public:
reference(std::vector<int>::reference ref) : ref_(ref) { }
operator int() const { return (int) this->ref_; }
reference& operator=(int x) { this->ref_ = x; return *this; }
private:
std::vector<int>::reference ref_;
};
reference operator[](unsigned int pos) {
return reference(this->vec_[pos]);
};
private:
std::vector<int> vec_;
};
int main() {
A a(10);
a[5] = 42;
std::cerr << a[5] << std::endl;
return 0;
}
Here, the program compiles fine if I remove the line virtual reference operator[](unsigned int pos) = 0; in the interface. However, I would like the array subscript operator to be part of the interface.
The error message thrown by G++ is invalid abstract return type for member function ‘virtual SomeInterface::reference SomeInterface::operator[](unsigned int)’.
I do understand why it fails. But I can't figure out any way to make something like this work. Can anybody explain why I am doing (or thinking) wrong?
You can not create objects of type SomeInterface::reference, since it is a pure abstract class, and that is what the compiler told you.
You need to return a reference (or a pointer) to such class. Like this :
virtual reference& operator[](unsigned int pos) = 0;
but then :
in derived classes, you shouldn't change the signature of the pure virtual methods. It should stay virtual SomeInterface::reference& operator[](unsigned int pos)
you can not return reference to a temporary object
btw take care how you create objects of such classes. They do not have virtual destructors.
Basically you can't return a reference to something that can never exist. However, you could use a pointer to an abstract class. That pointer will ultimately only be able to point to an instance of a derived class.
It is not clear exactly what you are trying to do. But you might look into Creation Patterns to find something close to what you need
Related
I have a base product class with a few private members and a public getter that derived classes inherit. I would like to disqualify instantiation, since the class is intended for use with an abstract factory. I thought protected con/destructors might work, however, this breaks my smart pointers. Friending seems like a useful disaster. Is there a well-known solution to this, or should I resign myself to the fact that any client who has the factory injected must also know enough to instantiate the base product?
class Product
{
private:
char type_name;
char size_name;
public:
Product(char, char);
virtual ~Product() {}
void Print();
};
Use a token key.
private:
Product(char, char);
struct key_t{explicit key_t(int){}};
static key_t key(){return key_t(0);}
public:
Product(key_t, char a, char b):Product(a,b){}
static std::shared_ptr<Product> make_shared(char a, char b){ return std::make_shared<Product>(key(),a,b); }
anyone with a Product::key_t can construct a Product without being a friend. And without the key, you cannot.
This lets Product pass creation-rights as a value.
Smart pointers with configurable destroy code can use similar techniques. But I'd just make the destructor public.
Your static member function, or friend function, which is the factory should have no problem with calling protected constructors and returning a smart pointer. Generally plan to return a std::unique_ptr<BaseClass> which can be converted into a std::shared_ptr if the caller wants that instead.
Make the virtual destructor public.
Update: Don't bother making the factory a friend. You only need to prevent the construction of the base and intermediate classes. Make them effectively hidden and private by hiding the implementation classes in their own source file. Or an anonymous namespace I suppose.
Here have some code of how I would do it:
#include <iostream>
#include <memory>
#include <string>
// ITest is the only class any other code file should ever see.
class ITest {
protected:
ITest() = default;
public:
virtual ~ITest() = 0;
virtual int getX() const = 0;
virtual int getY() const = 0;
};
// Destructors must always have an implementation even if they are pure virtual.
ITest::~ITest() {}
std::ostream &operator<<(std::ostream &os, const ITest &x) {
return os << '[' << x.getX() << ',' << x.getY() << ']';
}
// Declaration of constructTest factory function.
// Its definition should be hidden in a cpp file.
std::unique_ptr<ITest> constructTest(int x);
// The main function does not need to know anything except the ITest interface
// class and the constructTest function declaration.
int main(int argc, char *argv[]) {
int val = 0;
if (argc > 1)
val = std::stoi(argv[1]);
auto p = constructTest(val);
std::cout << *p << std::endl;
}
// These classes should be defined in a private header file or in a cpp file.
// Should not be visible to any other code. It has no business knowing.
// Hiding all of this implementation is sort of the point of abstract interface
// classes and factory function declarations.
class TestBase : public ITest {
private:
int x = 0;
int y = 0;
protected:
TestBase(int x = 0, int y = 0) : x(x), y(y){};
public:
int getX() const override { return x; }
int getY() const override { return y; }
};
class TestA final : public TestBase {
public:
TestA() = default;
};
class TestB final : public TestBase {
public:
TestB(int x, int y) : TestBase(x, y) {}
int getX() const override { return -TestBase::getX(); }
};
std::unique_ptr<ITest> constructTest(int x) {
// make_unique is c++14.
// For C++11 use std::unique_ptr<ITest>(new TestB(x, x)
if (x) {
return std::make_unique<TestB>(x, x);
// return std::unique_ptr<ITest>(new TestB(x, x));
}
return std::make_unique<TestA>();
}
The answer was to make the destructor a pure virtual AND to implement it with an empty body. That empty implementation is where I got tripped up. Print() doesn't need to be static.
Product.hpp
#include <memory>
class Product {
public:
virtual ~Product() = 0;
void Print();
protected:
char type_name{};
char size_name{};
private:
};
Product.cpp
#include "Product.hpp"
Product::~Product() {}
void Product::Print() {
//Print p
}
I have an accessor member function (e.g. operator[]) that is const-overloaded:
class Container {
public:
Foo& operator[](int i);
const Foo& operator[](int i) const{
return const_cast<Container *>(this)->operator[](i);
}
};
Here, const Foo& operator[] const is defined in this way so that the same thing is not defined twice.
Now I want to make Container a base class, and operator[] becomes virtual:
class BaseContainer {
public:
virtual Foo& operator[](int i) = 0;
const Foo& operator[](int i) const{
// Is this correct?
return const_cast<BaseContainer *>(this)->operator[](i);
}
};
class DerivedContainer : public BaseContainer {
public:
Foo& operator[](int i);
};
Since it is illegal to const_cast from const DerivedContainer * to BaseContainer *, I am not sure if this works in the case of polymorphism.
I would assume that the cast is still valid because the type of this would always be const BaseContainer * in BaseContainer::operator[] const because it is not virtual, but I am not sure if that's the correct way of doing this. Maybe it is simply better to define operator[] twice in this case?
would assume that the const_cast is still valid because the type of this would always be const BaseContainer * in BaseContainer::operator[] const because it is not virtual, but I am not sure if that's the correct way of doing this.
Your understanding is correct. The code should work as intended.
There is another thing you have to think about, though. When you declare
Foo& operator[](int i);
in the derived class, the const version is not going to be found if the function call is made on a derived class object/reference/pointer. To be able to use it with a derived class object/reference/pointer, add the following in the derived class.
using BaseContainer::operator[];
The overloaded non-const-version in DerivedContainer will be called from the body of BaseContainer::const operator[] due to polymorphism. So from this point it is actually a "legal" design, although your assumption "this would always be const BaseContainer * in BaseContainer::operator[] const because it is not virtual" is - in the context of polymorphism - wrong.
See the following code illustrating the call chain:
struct Base {
virtual void print() { cout << "Base.non-const;"; }
void print() const { cout << "entry:Base.const;then..."; const_cast<Base *>(this)->print(); }
};
struct Derived : public Base {
void print() override { cout << "Derived.non-const;"; }
};
int main() {
const Base* bc = new Derived;
bc->print();
//Output: entry:Base.const;then...Derived.non-const;
cout << endl;
Base* bnc = new Derived;
bnc->print();
// Output: Derived.non-const;
}
Note that the non-const-body of operator[] must not alter the *this-object if this object has originally been defined as const. Otherwise you get undefined behaviour.
I did a small exemple to try to explain you with my poor english what I want to do :).
I have a main class who is my engine. This is my parent class of several children.
this is the parent class :
#include <string>
#include <iostream>
#include <vector>
template <typename Type>
class A
{
public:
A(std::string const &str)
: m_str(str)
{
}
void run(void) const {
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++) {
if(m_str == ACTIONS[i].key) {
return ((*(this).*ACTIONS[i].f)(m_str));
}
}
}
protected:
typedef struct s_action {
std::string key;
void (Type::*f)(std::string const &);
} t_action;
static t_action const ACTIONS[];
std::string m_str;
};
class B : public A<B>
{
public:
B(std::string const &str);
protected:
static t_action const ACTIONS[];
void error(std::string const &str);
void success(std::string const &str);
};
I would like to call children method with table pointer of member function in this parent class A::run as you can see above
This code does not compile.
I know it's not possible to have a static variable virtual, but it's
exactly that I need to do have for A::ACTIONS. I absolutely need to initialise B::ACTIONS to A::run works.
In first Is it possible? Have you got a small exemple of this case?
This is the end of my small code :
#include "Class.hpp"
B::t_action const B::ACTIONS[] = {
{"ERROR", &B::error},
{"SUCCESS", &B::success},
{"", nullptr}
};
B::B(std::string const &str)
: A<B>(str)
{
}
void B::error(std::string const &str) {
std::cerr << str << std::endl;
}
void B::success(std::string const &str) {
std::cout << str <<std::endl;
}
And the main:
#include "Class.hpp"
int main() {
B b("SUCCESS");
b.run();
return (0);
}
I didn't try, normally this code should Display SUCCESS on stdout
Thank you for your help
void run(void) const
{
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++)
if (m_str == ACTIONS[i].key)
return ((*(this).*ACTIONS[i].f)(m_str));
}
There are multiple reasons why this fails to compile. Not one, but several reasons. This entire dispatching mechanism must be completely redesigned.
The first order of business is that this is a
void run(void) const
A const class method.
The method pointer in question is:
void (Type::*f)(std::string const &);
The method pointer is not const, but mutable. From an existing const class method, you can only invoke other const methods. You cannot invoke non-const methods, either directly or indirectly via a method pointer, from a const class methods.
So the first order of business is to change this to
void (Type::*f)(std::string const &) const;
This also means that all your methods, in the child class, error() and success(), must also be const class methods too.
If it's necessary to use this dispatch mechanism with non-const methods, the run() method cannot be a const class method itself. But this is not the only problem here, so I'll continue with the const method, at hand.
return ((*(this).*ACTIONS[i].f)(m_str));
The this here, is a A<Type>. This is a method of that class. That's what this is here.
The method pointer, f is pointer to a method of Type, not A<Type>. Type is a subclass of A<Type>, and you cannot convert a pointer or a reference to a base class to a pointer or a reference to a subclass, any more than you can take a pointer to A, and convert to a pointer to B when B inherits from A. C++ does not work this way.
The solution is simple, and requires only a few small tweaks. This run() should take a reference to const Type &, and invoke the method via the passed-in reference, then a replacement abstract run() method invokes it, passing *this as a parameter:
public:
virtual void run()=0;
protected:
void run_me(const Type &me) const
{
unsigned int i;
for(i = 0; ACTIONS[i].f != nullptr; i++)
if (m_str == ACTIONS[i].key)
return ((me.*ACTIONS[i].f)(m_str));
}
Then, each subclass that inherits this template only needs to implement a simple facade:
class B : public A<B>
{
public:
void run() const override
{
run_me(*this);
}
EDIT: This addresses the compilation error, but additional work is needed to deal with the fact that static class members cannot be overridden. The solution is also pretty simple: also leverage virtual class methods in order to implement this.
Remove the declaration of ACTIONS from the template base class, and replace it with an abstract function:
virtual const t_action *get_actions() const=0;
And use it in run_me():
const t_action *ACTIONS=this->get_actions();
The rest of run_me() remains as is, and then implement get_actions() in the child class:
const t_action *get_actions() const override
{
return ACTIONS;
}
Pretty much everything else remains the same.
The problem is that A will always use is own defined set of actions, not B's.
You don't need to create A at all, as you want to use B methods and list of methods.
Let's say that you create first a run call function:
template<typename T>
void run(T* obj, const std::string method)
{
const auto& available_methods = obj->get_methods();
auto iter = available_methods.find(method);
if(iter == available_methods.end())
{
// Handle this case
}
std::invoke(iter->second, obj); //C++17, or (obj->*(iter->second))();
}
Now for the class B, you need something very simple:
class B
{
public:
typedef std::unordered_map<std::string, void(B::*)()> MethodMap;
void foo();
static MethodMap& get_methods()
{
static MethodMap map{{"foo", &B::foo}};
return map;
}
};
Populate the map with get_methods() in the static function, and then call run through:
int main()
{
B b;
run(&b, "foo");
}
If you are going to use CRTP, IMO you need to google for CRTP first.
By the way here's a quick direct ans 2 your q:
template<typename crtp_child>
class crtp_base{
using crtp_target=crtp_child;
auto crtp_this(){
return static_cast<crtp_target*>(this);
};
auto crtp_this() const {
return static_cast<crtp_target const*>(this);
};
public:
void run(){
auto range=crtp_this()->actions.equal_range(m_str);
for(auto entry:range)
(crtp_this()->*(entry.second))(m_str);
};
protected:
crtp_base(std::string str):
m_str(str)
{};
std::string m_str;
//...
};
struct crtp_user:
crtp_base<crtp_user>
{
using crtp_base::crtp_base;//ctor fwding
protected:
friend class crtp_base<crtp_user>;
std::unordered_multimap<std::string, void (crtp_user::*)(std::string)> actions;
//...
};
This is a C++(11) question.
I have a object Obj myObj encapsulating an object f of type MyType.
Depending on runtime context, the object fshould behave differently.
One natural way of implementing this would be for the class Obj to encapsulate a pointer to an abstract base class MyType, which would, depending on the context point to different (public) child of MyType, such as MyType1, MyType2, etc.
However, I'm not very keen on Obj "suffering" the consequences of MyType being polymorphic, i.e. having to deal with a pointer. In particular, if I make it a std::unique_ptr<MyType>, it implies that Obj can either not be copied or that one needs to give it a proper copy constructor that deals with copying MyType ressources.
In my opinion, MyType being polymorphic shouldn't be Obj's problem.
I came with the following classes. Essentially the idea is to hide the pointer within MyTypeprivate attributes. In addition my second question concerns the fact that concrete implementations of MyTypeImpl may share some code shouldn't be repeated. I've put that in a class from which concrete implementations privately inherit.
I'm curious what more expert developers than me would think about it. Is it too heavy "just to hide the pointer"? Is there a better way to do it?
#include <iostream>
#include <memory>
// a "standard" implementation of MyType
class MyTypeImpl
{
public:
virtual double operator()(double a) = 0;
virtual int implType() const = 0;
virtual void complexStuff() const = 0;
};
// some internal stuff common to all implementations
class MyTypeImplInternals
{
protected:
MyTypeImplInternals(int value):factor_{value}{}
int factor_;
void longCommonFunction() const{ std::cout << "I'm doing complex stuff common to all interfaces " << factor_ << "\n" ;}
};
// one specific implementation
class MyTypeImpl1: public MyTypeImpl, private MyTypeImplInternals
{
public:
MyTypeImpl1(int factor):MyTypeImplInternals{factor}{};
virtual double operator()(double a) override {return factor_*a;}
virtual int implType() const override {return 1;}
virtual void complexStuff() const override { longCommonFunction(); }
};
// a second implementation
class MyTypeImpl2: public MyTypeImpl, private MyTypeImplInternals
{
public:
MyTypeImpl2(int factor):MyTypeImplInternals{factor}{};
virtual double operator()(double a) override {return factor_*a;}
virtual int implType() const override {return 2;}
virtual void complexStuff() const override { longCommonFunction(); }
};
class MyTypeImplFactory
{
public:
static std::unique_ptr<MyTypeImpl>createMyTypeImpl(int implementationType)
{
switch(implementationType)
{
case 1:
return std::unique_ptr<MyTypeImpl> (new MyTypeImpl1(12));
case 2:
return std::unique_ptr<MyTypeImpl> (new MyTypeImpl2(22));
default:
throw std::runtime_error("implementation does not exist...\n");
return nullptr;
}
}
};
// my type
class MyType
{
public:
MyType(int implementationType)
{
implPtr_ = MyTypeImplFactory::createMyTypeImpl(implementationType);
}
MyType(MyType const& source)
: implPtr_{ MyTypeImplFactory::createMyTypeImpl(source.implType()) }
{
}
double operator()(double a){return (*implPtr_)(a);}
int implType() const {return implPtr_->implType();}
void complexStuff() const {implPtr_->complexStuff();}
private:
std::unique_ptr<MyTypeImpl> implPtr_;
};
class Obj
{
private:
MyType f;
public:
Obj(int dim):f{dim}{}
Obj(Obj&& sourceToMove) = default;
Obj(Obj const& source) = default;
void doStuff() {std::cout << "I'm doing stuff() " << f(2) << std::endl; f.complexStuff();}
};
int main()
{
Obj myObj{1}, myObj2{2};
myObj.doStuff();
myObj2.doStuff();
Obj myObj3{std::move(myObj2)}; // myObj2 now dead
Obj myObj4{myObj};
myObj3.doStuff();
myObj4.doStuff();
}
link to online compiler : http://cpp.sh/8rhyy
Here the implementations are very dumb ones to serve as an example. An application for this design could be for instance a Solver (Obj) that solves some kind of physics Equation (MyType) which exact definition depends on the dimensionality of the problem, equation in 1D space is not the same as in 2D or in 3D. Solver's code would be completely independent on Equation's dimensionality and also wouldn't have to deal with a pointer. Equation would hide its 1D, 2D, or 3D implementation from outside's world.
(was originally a post on code review that was put on Hold because to abstract)
This proposed class design appears to have an obvious problem. The polymorphic type is referenced by a std::unique_ptr:
std::unique_ptr<MyTypeImpl> implPtr_;
Obj's default copy constructor, and assignment operator will end up transferring the held pointer to the new object, leaving the std::unique_ptr in the original object staring at a nullptr. Not good.
At the bare minimum this should be either a std::shared_ptr, or Obj's copy constructor and assignment operator will need to instantiate a new implPtr_. Note that with the easy std::shared_ptr fix the result of the copy constructor and an assignment operator is having multiple instances of Obj referencing the same instance of MyTypeImpl, which may or may not be an issue.
A much simpler class design is simply have MyTypeImpl1 and MyTypeImpl2 be subclasses of Obj, implementing the required polymorphic behavior.
I just refactored your codes.
#include <iostream>
#include <memory>
// !abstraction
class MyType
{
public:
virtual double operator()(double a) = 0;
virtual int implType() const = 0;
virtual void complexStuff() const = 0;
};
// !!MyTypeImplInternals could be a super class of MyTypeImpl* if it has properties(such as factor_) or just some static functions.
class MyTypeImplInternals
{
public:
MyTypeImplInternals(int value):factor_{value}{}
int factor_;
void longCommonFunction() const{ std::cout << "I'm doing complex stuff common to all interfaces " << factor_ << "\n" ;}
};
// one specific implementation
class MyTypeImpl1: public MyType
{
MyTypeImplInternals internal_;
public:
MyTypeImpl1(int factor):internal_{factor}{};
virtual double operator()(double a) override {return internal_.factor_*a;}
virtual int implType() const override {return 1;}
virtual void complexStuff() const override { internal_.longCommonFunction(); }
};
// a second implementation
class MyTypeImpl2: public MyType
{
MyTypeImplInternals internal_;
public:
MyTypeImpl2(int factor):internal_{factor}{};
virtual double operator()(double a) override {return internal_.factor_*a;}
virtual int implType() const override {return 2;}
virtual void complexStuff() const override { internal_.longCommonFunction(); }
};
std::unique_ptr<MyType> createMyType(int implementationType)
{
switch(implementationType)
{
case 1:
return std::unique_ptr<MyType> (new MyTypeImpl1(12));
case 2:
return std::unique_ptr<MyType> (new MyTypeImpl2(22));
default:
throw std::runtime_error("implementation does not exist...\n");
return nullptr;
}
}
class Obj
{
private:
std::unique_ptr<MyType> f_;
public:
Obj(int dim):f_(createMyType(dim)){}
Obj(Obj&& sourceToMove) : f_(std::move(sourceToMove.f_)) {}
Obj(Obj const& source) : f_(createMyType(source.f_->implType())) {}
void doStuff() {std::cout << "I'm doing stuff() " << (*f_)(2) << std::endl; f_->complexStuff();}
};
int main()
{
Obj myObj{1}, myObj2{2};
myObj.doStuff();
myObj2.doStuff();
Obj myObj3{std::move(myObj2)}; // myObj2 now dead
Obj myObj4{myObj}; //!!Bad idea to share an implementation to more Objs.
myObj3.doStuff();
myObj4.doStuff();
}
suppose I have those 2 classes:
class num{
public:
int a;
num(){};
num(int x):a(x){};
num(const num& n):a(n.a){}
virtual bool operator==(const num& n)const = 0;
virtual ~num(){};
};
class tmp: public num{
public:
tmp(){};
tmp(int x):num(x){};
tmp(const num& n): num(n){}
tmp(const tmp& t): num(t.a){}
virtual bool operator==(const num& n)const{
return tmp(n).a == a;
}
virtual ~tmp(){};
};
and something like this in main:
int main() {
num* x = &get(...);
return 0;
}
get return a reference of type tmp (in this case. in general it returns reference to a type that inherits from num)
what I want to do is create another num* y that will point to a copy of *x so that if I change *y I won't change *x. and I can't quite figure out how to do this since num is abstract so I can't create an object of this type to make a copy.
ok and another question.
if I overload << operator:
std::ostream& operator<<(std::ostream& os, const tmp& t){
return os<<t.a<<endl;
}
and then try to do this:
cout<<*x<<endl;
I get an error no match for 'operator<<'
why is that?
You're looking for the prototype pattern, also often called clone pattern.
It's basically a pure virtual method
virtual std::unique_ptr<num> clone() const = 0;
... that you declare in num, to be overriden by each derived class. You then just call x->clone(); to get a brand new object of the correct type.
You'll need a virtual function to clone an object based on its dynamic type. It will have to return a (preferably smart) pointer to a newly allocated object of the correct type. For example:
class num {
public:
virtual std::unique_ptr<num> clone() const = 0;
// other members...
};
class my_num : public num {
public:
virtual std::unique_ptr<num> clone() const {
return std::make_unique<my_num>(*this);
}
// other members...
};
int main() {
num* x = &get(...);
auto y = x->clone();
}