I want to create an abstract class with a pure virtual private method but I can't implement that in my concrete class. My option is to make that pure virtual private method to protected but in my concrete class I want to make it only a private. Like,
class IFoo
{
public:
IFoo(){}
virtual ~IFoo(){}
protected:
virtual void fooMethod() = 0;
};
class Foo : public IFoo
{
public:
Foo(){}
virtual ~Foo(){}
private:
virtual void fooMethod() {}
};
Is there any implication doing this? Or this is just fine?
Thanks!
Why can't you make the method private in the base class? Making them private is a pretty standard design pattern for C++. Then the base class implements public/protected methods that call the private ones.
http://www.gotw.ca/publications/mill18.htm has way more info on the uses of public/private/protected virtual methods.
Related
I have a BASE class implementing a virtual method f(). I also have a INTERFACE class, that has a pure virtual method f(). I then have a DERIVED class that inherits both the BASE and the INTERFACE. When I try to instantiate DERIVED I get an compiler error "cannot instantiate abstract class".
class BASE
{
public:
BASE() = default;
~BASE() = default;
virtual void f(){}
};
class INTERFACE
{
public:
virtual void f() = 0;
};
class DERIVED :
public INTERFACE, public BASE
{
public:
DERIVED() = default;
~DERIVED() = default;
};
BASE class does not know INTERFACE, it is part of a library and I can not change it.
I read a few similar questions, but I could not find a clear answer as to how to solve this. What I need is to be able to instantiate DERIVED and be able to use f() from BASE in DERIVED as well as when I access it through INTERFACE.
Because the void f() of INTERFACE is never defined, BASE does not inherit from INTERFACE, so that is not an override of that function.
DERIVED does not define a void f(), so it also does not override that INTERFACE function, so that function has no body.
If you would want it to use the BASE::f to override INTERFACE::f(), either inherit BASE from INTERFACE or add an override in your DERIVED as such:
void f() override {BASE::f();}
Maybe I didn't make my question clear, the following answers are not answering my question. Let me make the question more specific. My question is that I have a base class to send to clients so that clients can develop derived classes at their ends. How can I hide the private methods and members?
For example, in the following code snippets, the base.h file declares the base class which provides three private virtual methods for clients to override in the derived classes. The clients can override none, any, or all of them. Assuming a client developed a derived class called "Derived", and passed the "Derived" class creator to me so that I can create the Derived class somewhere, e.g. Base* p_base = new Derived() and call p_base->Execute() to actually call client implementations of virtual functions DoInitialize(), DoExecute(), DoCleanUp().
BTW: I don't think opaque pointers will work.
In Base.h file:
class Base {
public:
Base();
~Base();
void Execute();
private:
// virtual functions to be overridden by derived classes.
virtual void DoInitialize() {}
virtual void DoExecute() {}
virtual void DoCleanUp() {}
private:
// private members and functions that are intended to hide from clients
std::vector<float> data_;
....
}
In Base.cpp file
Base::Execute() {
DoInitialize();
DoExecute();
DoCleanUp();
}
In clients end
class Derived : public Base {
public:
Derived();
~Derived();
private:
// overide base class methods
void DoInitialize() {}
void DoExecute() {}
void DoCleanUp() {}
}
In my end somewhere:
void main() {
Base* p = DerivedCreater(); // creater a Derived class, assumes DerivedCreater() has passed in by clients.
p->Execute(); // I want to call the client implementation of DoInitialize(), DoExecute(), and DoCleanUp()
}
The way to go is to have an opaque pointer to the implementation.
class BaseImpl;
class Base {
public:
Base();
~Base();
private:
// virtual functions to be overridden by derived classes.
virtual void Initialize() {}
private:
// private members and functions that are not intended to override by derived classes
void Configure() { m_impl->Configure(); }
BaseImpl* m_impl;
}
Then, in the BaseImpl, you keep a pointer to the Base and you call the virtual functions as wanted. You keep BaseImpl.h in your private includes and you don't distribute it to the library users.
See:
https://en.cppreference.com/w/cpp/language/pimpl
I have the following interfaces and classes
public interface IBase
{
virtual void SomeBaseMethod()=0;
}
public interface IDerived : IBase
{
virtual void SomeOtherMethod()=0;
}
public class base: public IBase
{
void SomeBaseMethod(){};
}
public class derived: public base, public IDerived
{
void SomeBaseMethod(){};
void SomeOtherMethod(){};
}
In class derived, I have to repeat 'void SomeBaseMethod(){};', which have already implement in my class base. Otherwise I will get compile error. Is it possible not repeat 'void SomeBaseMethod(){};' in my class derived?
Unfortunately, you have to repeat yourself here. C++ has virtual inheritance, which would solve this problem, but you can't use virtual inheritance with COM interfaces. Here's an explanation as to why.
Lets suppose you want to make an interface of the class Derived and it looks like this:
class Derived : public Base
{
public:
foo();
}
class Base
{
public:
tii();
//many other methods
}
How would you do the Interface? How can you make Base::tii visible (and also other methods) to this new interface?
class IDerived
{
public:
virtual foo() = 0;
// should I declare here tii() as a pure virtual function?
// but by doing it now there is ambiguity!
}
What is a good strategy?
The new Derived class should look like this....
class Derived : public Base, public IDerived
{
//implement the real thing
}
Your example is doing things backwards: the interface should be defined independently of any concrete classes with all pure virtual methods:
class IDerived
{
public:
virtual void foo() = 0;
virtual ~IDerived() {} // don't forget to include a virtual destructor
}
And the concrete classes will derive publicly from the interface:
class Derived : public Base, public IDerived
{
public:
void foo();
}
If you want IDerived to also declare methods that Derived inherits from Base, you can have Derived explicitly implement the method by calling the inherited implementation:
class Derived : public Base, public IDerived
{
public:
void foo();
void bar() { Base::bar(); }
}
At front, I dislike interfaces (they are grown by other languages than c++).
Anyway, if you have one, it should be complete: Hence have the 'tii() as a pure virtual function'. To resolve the conflict rewrite that function in 'Derived' (forward to Base::tii).
I have the following code:
class Interface
{
virtual void method()=0;
};
class Base : public Interface
{
virtual void method()
{
//implementation here
}
};
class Parent: public Interface
{
};
class Child : public Base, public Parent
{
};
int main()
{
Child c;//ERROR: cannot instantiate abstract class
}
Now I know why this is happening, since I'm inheriting Parent then I have to implement method again. But it's already defined in Base class and I don't want to override that definition for every child class. I think there was some standard way of getting rid of this in c++ (telling compiler which copy of Interface should it use) I just can't remember what it was.
What you are talking about is called dominance.
From the linked article:
class Parent
{
public:
virtual void function();
};
class Child1 : public virtual Parent
{
public:
void function();
};
class Child2 : public virtual Parent
{
};
class Grandchild : public Child1, public Child2
{
public:
Grandchild()
{
function();
}
};
You have a diamond-shaped hierarchy but are not using virtual inheritance.
As a result, you end up with two distinct virtual method() functions in your Child class.
One way to fix it is to move to using virtual inheritance. This way you'll only have a single Child::method() and won't need two implementations.
Pure virtual functions must be defined in the derived class.
If you don't do so, your derived class (in this case "child") will itself become an abstract class which can't be instantiated and hence the error.