I'm implementing a static polymorphism:
template<typename T>
class Base {
public:
void method() {
// do something
impl();
// do something else
}
void impl() { // intended to be private
static_cast<T*>(this)->impl();
}
};
class Derived : public Base<Derived> {
public:
void impl() { // intended to be private
}
};
This code is a static implementation of a dynamic polymorphic classes where void impl() was pure virtual. So the base class was abstract.
Now these classes implement static polymorphism and therefore don't have pure virtual functions.
Is it possible to make Base class abstract, so that objects of this class can't be created?
You can use a protected destructor and constructors:
template<typename T>
class Base {
public:
void method() {
// do something
impl();
// do something else
}
void impl() { // intended to be private
static_cast<T*>(this)->impl();
}
protected:
Base() = default;
~Base() = default;
// If you don't want to implement proper copying/moving:
// Base(const Base&) = delete;
// Base(Base&&) = delete;
// Base& operator=(const Base&) = delete;
// Base& operator=(Base&&) = delete;
};
This will even disallow a derived class's member functions to create base class objects, as well as trying to delete a pointer whose static type is Base<T>.
Related
class Base
{
public:
virtual void f()
{
g();
}
virtual void g()
{
cout<<"base";
}
};
class Derived : public Base
{
public:
virtual void f()
{
Base::f();
}
virtual void g()
{
cout<<"derived";
}
};
int main()
{
Base *pBase = new Derived;
pBase->f();
return 0;
}
In this program I have kept both derived and base class functions as virtual. Is it possible call virtual functions of derived class through base class pointer and base class functions are not virtual.
Thanks in advance..
assuming functions in base class are not virtual
This can be achieved via type erasure. But there are caveats.
Your "base" class should decide between the two:
Being a view class (can't be called delete on or created by itself)
Being a resource owning class (implemented similar to 1, but stores a smart pointer).
Here is an example for case 1: https://godbolt.org/z/v5rTv3ac7
template <typename>
struct tag{};
class base
{
public:
base() = delete;
template <typename Derived>
explicit base(tag<Derived> t)
: _vTable(make_v_table(t))
{}
int foo() const { return _vTable.foo(*this); }
protected:
~base() = default;
private:
struct v_table
{
virtual int foo(const base &b) const = 0;
protected:
~v_table() = default;
};
template <typename Derived>
static const v_table& make_v_table(tag<Derived>){
struct : v_table
{
int foo(const base &b) const {
return static_cast<const Derived&>(b).foo();
}
} static const _vTable{};
return _vTable;
}
private:
const v_table& _vTable;
};
class derived : public base
{
public:
explicit derived()
: base(tag<derived>{})
{}
int foo() const { return 815; }
};
// example
#include <iostream>
int main(){
derived d{};
const base& b = d;
std::cout << b.foo() << '\n';
}
Take notice, that you can only take a pointer or a reference (cv-qualified) to a base class. The base class can't be created on its own.
Also tag<T> is needed to call a templated constructor.
DO NOT CALL DERIVED METHODS IN THE BASE CONSTRUCTOR OR DESTRUCTOR
Simple answer is no, if the function you are calling is not virtual. The Compiler would have no Idea that you are trying to call a function from the Derived Class, and won't make and I'm paraphrasing here since I do not know the proper term for,"Won't make proper entries in the Virtual Table".
class Base
{
public:
void f()
{
std::cout<<"Base f() Called\n";
g();
}
virtual void g()
{
std::cout<<"Base g()\n";
}
virtual ~Base(){std::cout<<"Base Destroyed\n";}
};
class Derived : public Base
{
public:
void f()
{
g();
}
virtual void g()
{
std::cout<<"Derived g()\n";
}
~Derived(){std::cout<<"Derived Destroyed\n";}
};
int main()
{
Derived* D1 = new Derived();
Base* B1 = D1;
B1->f();
delete B1;
return 0;
}
Have a look at the following code, I have not declared Base::f() as virtual,calling B1->f() calls the Base Method, but the base method calls a virtual function Base::g() and this allows the "Derived" method be called.
Have a look at this thread or this blogpost to understand Virtual Tables.
(1) and you must ALWAYS declare the destructor of a base class virtual when destroying Derived Object through a Base Pointer, else the resources used by the Derived Object will never get destroyed and it's memory will leak until the program closes.
Don't Take my word as gospel, I am simply passing on knowledge I have acquired from first hand experience, Except for (1), specially if you are not using smart pointers
Consider the following code. I want the convert function to work without defining the T(const Base&) copy constructor in every concrete derived type of Base.
It could be done in the intermediate class CRTP<T> in the way illustrated only if it is not abstract, but it is abstract. So how can I make it work in this case?
struct Base {
virtual void foo() = 0;
};
template <typename T>
struct CRTP : virtual Base {
CRTP (const Base& base) : Base(base) { }
CRTP() = default;
// virtual void foo() override { } // CRTP<T> is abstract.
};
struct Derived1 : CRTP<Derived1> {
Derived1 (const Base& base) : Base(base) { }
Derived1() = default;
virtual void foo() override { }
};
struct Derived2 : CRTP<Derived1> {
Derived2 (const Base& base) : Base(base) { }
Derived2() = default;
virtual void foo() override { }
};
template <typename T, typename U>
T* convert (const U& u) {
// return new T(u); // This works, but only if T(const Base&) constructor is defined in every Base concrete derived type.
return dynamic_cast<T*>(new CRTP<T>(u)); // This only works if CRTP<T> is not abstract.
}
int main() {
Derived1 d1;
Derived2* d = convert<Derived2, Derived1>(d1);
}
But, as a matter of fact, it is not a copy constructer, so it could be simply delegated like this:
struct Derived1 : CRTP<Derived1> {
using CRTP<Derived1>::CRTP;
Derived1() = default;
virtual void foo() override {
}
};
You can also use a pointer instead of a reference, which seems more relevant in your code by the way, because convert() returns a pointer. Such constructor is not considered as a copy constructor and can always be delegated to the children.
If i have a base class Base:
class Base {
public:
bool foo;
virtual bool bar() = 0;
virtual ~Base() = default;
};
And two derived classes:
class Derived1 : public Base
{
Derived1();
bool bar() override;
}
class Derived2 : public Base
{
Derived2();
std::vector<baz*> bazVector;
bool bar() override;
}
And i have a vector std::vector<Base*> mainVector which us populated like this:
mainVector.push_back(someDerivedPointer)
At some point i need to determine what object is stored: Derived1 or Derived2, so i could access Derived2->bazVector if object is Derived2
One solution is trying to dynamic_cast<Derived2>(mainVector.at(someIndex)) and check for returned nullptr, or storing some enum that would tell me what class this object belongs to, but these solutions seem crutchy, and i wonder if there is a better solution.
As advised in the comment section, you are probably looking the wrong direction.
There's high chance you are not tackling the problem with the right approach.
If you need to write different logic based on the actual derived class from a pointer, you are missing something.
We don't have too much details, but for what you said, you have two options:
1: adding a virtual method to retrieve your vector:
class Base {
public:
bool foo;
virtual bool bar() = 0;
virtual ~Base() = default;
virtual std::vector<baz*> getVector() = 0;
};
class Derived1 : public Base
{
public:
Derived1();
bool bar() override;
virtual std::vector<baz*> getVector() override {return {};};
}
class Derived2 : public Base
{
std::vector<baz*> bazVector;
public:
Derived2();
bool bar() override;
virtual std::vector<baz*> getVector() override {return bazVector;};
}
2: insert the logic where you need this vector into a virtual function (this is probably the better):
class Base {
public:
bool foo;
virtual bool bar() = 0;
virtual ~Base() = default;
virtual void doSomething() = 0;
};
class Derived1 : public Base
{
public:
Derived1();
bool bar() override;
virtual void doSomething() override {/*no op*/};
}
class Derived2 : public Base
{
std::vector<baz*> bazVector;
public:
Derived2();
bool bar() override;
virtual void doSomething() override {/*do something with you bazVector*/};
}
The other answer is most likely the best way to go forward in OP's case, but considering how vague the question's title is, there is an alternative idiom that is sometimes useful when:
All the derived classes of Base are known ahead of time.
The derived classes are particularly heterogenous, and creating a lowest-common-denominator interface would be problematic in some way, shape, or form.
A good example of this would be an AST. clang's ASTConsumer uses a flavor of the technique.
The visitor. The basic idea is to have an external interface with virtual methods for each derived class, and have a single virtual function in Base that dispatches this to the correct function.
class Derived1;
class Derived2;
class Base {
public:
class Visitor {
public:
virtual void operator()(Derived1&) {}
virtual void operator()(Derived2&) {}
protected:
~Visitor() = default;
};
virtual void visit(Visitor& v) = 0;
virtual ~Base() = default;
};
class Derived1 : public Base
{
public:
Derived1(){}
void visit(Base::Visitor& v) override { v(*this); }
};
class Derived2 : public Base
{
public:
Derived2(){}
void visit(Base::Visitor& v) override { v(*this); }
};
// Usage example:
struct MyVisitor final : public Base::Visitor {
void operator()(Derived1& obj) override {
std::cout << "1\n";
}
void operator()(Derived2& obj) override {
std::cout << "2\n";
}
};
int main() {
std::vector<std::unique_ptr<Base>> bases;
bases.push_back(std::make_unique<Derived1>());
bases.push_back(std::make_unique<Derived2>());
MyVisitor v;
for(auto& b : bases) {
b->visit(v);
}
}
I am having some problems with automatic typecasting between shared_ptr of inherited classes.
My class structure is as follows, a base class Base and two derived classes Derived1 and Derived2.
// Base class
class Base {
protected:
...
...
public:
Base() = default;
virtual ~Base() = default;
virtual void run() = 0;
...
...
};
// Derived class
class Derived1: Base {
protected:
...
...
public:
Derived1() = default;
virtual ~Derived1() = default;
void run() {...}
...
...
};
// Derived class
class Derived2: Base {
protected:
...
...
public:
Derived2() = default;
virtual ~Derived2() = default;
void run() {...}
...
...
};
I have a function doSomething()
void doSomething(std::shared_ptr<Base> ptr) {
ptr->run();
...
}
I call the function with the derived classes like so -
doSomething(make_shared<Derived1>())
doSomething(make_shared<Derived2>())
But I get an error saying -
no viable conversion from 'shared_ptr<class Derived1>' to 'shared_ptr<class Base>'
no viable conversion from 'shared_ptr<class Derived1>' to 'shared_ptr<class Base>'
What am I doing wrong? Is it safe just to use static_pointer_cast to the Base type? Like -
doSomething(static_pointer_cast<Base>(make_sahred<Derived2>()))
SOLUTION
My bad... The problem was that I was inheriting the base class privately.
As far as I can tell, the code that you've presented compiles fine: http://ideone.com/06RB2W
#include <memory>
class Base {
public:
Base() = default;
virtual ~Base() = default;
virtual void run() = 0;
};
class Derived1: public Base {
public:
Derived1() = default;
virtual ~Derived1() = default;
void run() {}
};
class Derived2: public Base {
public:
Derived2() = default;
virtual ~Derived2() = default;
void run() {}
};
void doSomething(std::shared_ptr<Base> ptr) {
ptr->run();
}
int main() {
doSomething(std::make_shared<Derived1>());
doSomething(std::make_shared<Derived2>());
}
#include <iostream>
#include <memory>
#include <cstdlib>
class IBase
{
public:
IBase() = default;
virtual ~IBase() = default;
virtual void f1() = 0;
};
class IDerived
{
public:
IDerived() = default;
virtual ~IDerived() = default;
virtual void f2() = 0;
};
class BaseImpl : public IBase
{
public:
BaseImpl() = default;
virtual ~BaseImpl() override = default;
virtual void f1() override { /* serious code */}
};
class DerivedImpl : public BaseImpl, public IDerived
{
public:
DerivedImpl() = default;
virtual ~DerivedImpl() override = default;
virtual void f2() override { /* serious code */}
};
class Base : public IBase
{
public:
Base() : m_impl(std::make_shared<BaseImpl>()) {}
virtual ~Base() override = default;
virtual void f1() override { m_impl->f1(); }
protected:
Base(const std::shared_ptr<BaseImpl>& impl) : m_impl(impl) {}
std::shared_ptr<BaseImpl> m_impl;
};
class Derived : public Base, public IDerived
{
public:
Derived() : Base(std::make_shared<DerivedImpl>()) {}
virtual ~Derived() override = default;
virtual void f2() override { impl()->f2(); }
private:
std::shared_ptr<DerivedImpl> impl() { return std::dynamic_pointer_cast<DerivedImpl>(m_impl); }
};
int main()
{
Base base;
base.f1();
Derived derived;
derived.f1();
derived.f2();
std::cin.sync();
std::cin.get();
return EXIT_SUCCESS;
}
It works, but it looks so weird that I might just give up pimpl.
Imagine having your Base defined like this:
class Base {
public:
Base();
virtual ~Base();
virtual void f1();
protected:
class Impl;
Impl *p_impl; // or shared_ptr, or unique_ptr, or whatever you like.
};
Note that there is nothing defined of Base::Impl. This is a very important part of the PIMPL idiom as you might have to use elements in the Impl class that require #include-ing things you don't want to include in the header class.
The derived class would then look like this:
class Derived: public Base {
public:
Derived();
~Derived();
virtual void f1(); // or not, depends
virtual void f2();
protected:
class Impl2;
Impl2 *p_impl2; // note that Derived::Impl2 might inherit from Base::Impl
};
This still hides the implementation details of both Base and Derived in Base::Impl and Derived::Impl2, while giving you complete freedom to implement Derived in any way you like (including inheritance).
Your Impl classes should only contain private variables and methods.
Don't put anything that that need to be accessible from children class there. Sub-classing the Impl class is wrong way to go in C++ because that defeats the purpose of this pattern.