I have a base class that I'd like to prevent inheritance by most classes, but allow it for a handful of classes that I can hard code in. Is this possible in C++? Is it easier with C++11?
I thought perhaps I'd use the final argument, but that prevents any inheritance at all.
// This can be derived by anyone
class Base{
...
}
// This should only be derived by those I say can derive it
class Base2: public Base{
protected:
int SpecialVar;
}
The reason I want this is that some classes need to have access to SpecialVar while it doesn't make sense for the other classes. It still makes sense for all classes to have the functionality of Base.
Instead of making your derived classes friends, another way (that may or may not make sense, depending on the concrete classes you're dealing with), is to nest them.
class Base {
Base() { }
public:
class Derived;
};
class Base::Derived : Base {
};
class CannotDerive : Base {
};
int main() {
Base::Derived x; // ok
CannotDerive y; // error
}
class X
{
private:
X() {}
friend class D;
};
class D: public X
{
};
class Y: public X // will fail, because it can't access X::X()
{
};
Other possibility is with a private destructor (specially if A is an abstract class, since you don't need instances of A):
class A
{
private:
virtual ~A() = 0;
};
A::~A() {}
class B : public A // Compilation error: ~A() is private.
{};
However, if B is one of your classes with permission to inherit from A, make it friend of A:
class A
{
private:
friend class B;
virtual ~A() = 0;
};
A::~A() {}
class B : public A // Fine.
{};
Related
In C++, if I have a abstract base class, is it possible to prevent its derived classes being instantiated by classes other than friends that the base class knows?
You can define constructors as private, just like any other function. For example:
class foo
{
friend foo *FooConstructor(void);
public:
void Method();
void Method2();
private:
foo();
foo(const &foo);
};
foo *FooConstructor(void)
{
return new foo();
}
This prevents a foo being created in any way, save with the FooContructor function.
There are two ways you can have a base-class internal
The first is to make the constructors private, like this:
struct Sub1;
struct Sub2;
struct Base
{
virtual ~Base() = default;
private:
Base() = default;
Base(const Base&) = default;
friend struct Sub1;
friend struct Sub2;
};
struct Sub1 : protected Base {}; // ok, its a friend
struct Sub2 : protected Base {}; // ok, its a friend
struct Sub3 : protected Base {}; // compiler error
The second way is to declare the base-class in a anonymous namespace:
namespace {
struct Base{};
}
struct Sub : Base {};
Now, all classes in the same translation unit can use Base,
but other classes wont know it exists.
This way is often less desirable, since derived classes can only
be used as incomplete types (forwarded)
The following example is from the book "Inside C++ object model"
class Abstract_base {
public:
virtual ~Abstract_base () = 0;
virtual void interface () const = 0;
virtual const char* mumble () const
{
return _mumble;
}
protected:
char *_mumble;
};
The author says if I want to initialize _mumble, the data member of the pure virtual base class, a "protected constructor" should be implemented.
But why protected? And why "public constructor" is not suitable for this class?
Thanks for your answers, and it would be perfect if there's an example.
It doesn't really matter, since you're not allowed to construct objects of the base class anyway. Making it protected serves only as a reminder of the fact that the class is supposed to be a base class; it's only cosmetics/documentation.
Consider
struct Base {
virtual ~Base() = 0;
protected:
Base() { std::puts("Base constructor"); }
};
Base::~Base() { std::puts("Base destructor"); }
struct Derived : Base {};
int main()
{
//Base b; // compiler error
Derived d;
Base *b = new Derived();
delete b;
}
Removing the protected doesn't change the meaning of the program in any way.
Abstract classes and construction of such
It doesn't matter if the constructor is public or protected, since an abstract class cannot be instantiated.
You must inherit from it in order to have it's constructor called, and since the Derived class calls the constructor of the abstract class it doesn't matter what protection level you choose, as long as the Derived class can access it.
One reason that one could possibly have for making it protected is to serve as a reminder that the class must be constructed through inheritance, but honestly that should be clear enough when seeing that it has pure virtual member-functions.
example snippet
struct B {
virtual void func () = 0;
virtual ~B () = 0 { };
};
B::~B () { }
struct D : B {
void func () override;
};
int main () {
B b; // will error, no matter if Bs ctor is 'public' or 'protected'
// due to pure virtual member-function
D d; // legal, D has overriden `void B::func ()`
}
A pure virtual class cannot be instantiated, so it doesn't make a difference if the constructor is public or protected.
A public constructor is syntactically correct. However, making it protected will carry a stronger indication that the class cannot be instantiated.
For an example: http://ideone.com/L66Prq
#include <iostream>
using namespace std;
class PublicAbstract {
public:
PublicAbstract() { }
virtual void doThings() =0;
};
class ProtectedAbstract {
protected:
ProtectedAbstract() { }
public:
virtual void doMoreThings() =0;
};
class B: public PublicAbstract {
public:
void doThings() { }
};
class C: public ProtectedAbstract {
public:
void doMoreThings() { }
};
int main() {
B b;
C c;
return 0;
}
A public constructor would not be very useful, since abstract classes cannot be instantiated in the first place.
A protected constructor makes sense: this way, a derived concrete class can provide its own public constructor that chains to the protected constructor of the base abstract class.
Protecetd ctor will make sure the ctor gets called by only the classes which derive from Abstract_base.
Public ctor is not suitable because the class contains a pure virtual method! How are you planning to instantiate a pure-virtual class if not via its child classes?
I have not programmed in c++ in a long time and want some simple behavior that no amount of virtual keywords has yet to produce:
class Base {
public:
int both() { return a(); }
};
class Derived : public Base {
protected:
int a();
};
class Problem : public Derived {
};
Problem* p = new Problem();
p.both();
Which gives me a compile-time error. Is this sort of behavior possible with c++? Do I just need forward declaration? Virtual keywords on everything?
No. You will have to use a pure virtual a in base.
class Base {
virtual int a() = 0;
int both() {
return a();
}
};
You should declare the a() function as a pure virtual method in the Base class.
class Base {
int both() {
return a();
}
virtual int a()=0;
};
Then implement the a() method in the Derived class
class Derived : public Base {
int a(){/*some code here*/}
};
And finally, Problem class doesn't see the both() method, since its private in Base. Make it public.
class Base {
public:
int both() {
return a();
}
};
Your function both() is private by default. Try:
class Base {
public:
int both() {
// ...
(In the future, it would be helpful if you tell us what the actual error message was.)
You need a() to be declared in class Base, otherwise the compiler doesn't know what to do with it.
Also, both() is currently a private method (that's the default for classes), and should be made public in order to call it from main.
You have multiple problems in your code :
unless you declare them public or protected, elements of a class are private as a default.
you need a virtual keyword to define a virtual function that would be callable in a parent.
new returns a pointer to Problem.
Here's a complete working code based on your test :
class Base {
protected:
virtual int a()=0;
public:
int both() {
return a();
}
};
class Derived : public Base {
private :
int a()
{
printf("passing through a!");
return 0;
}
};
class Problem : public Derived {
};
int main(void)
{
Problem* p = new Problem();
p->both();
}
tested on CodePad.
As others point out, you need to declare a() as pure virtual method of Base and change access to public to make your snippet work.
Here is another approach possible in c++: instead of virtual functions, you can use static polymorphism via the Curiously recurring template pattern:
template <class D>
class Base : public D
{
public:
int both() { return D::a(); }
};
class Derived : public Base<Derived>
{
public:
int a();
};
I'm posting this approach since you're asking what is possible in c++. In practice, virtual methods are most often a better choice because of their flexibility.
I have 6 classes which all perform the same actions. I would like to move common behavior to a common [base] class.
There are actions to be performed on 6 separate objects. The six objects are located in derived classes. Intuitively, the private member objects would be accessed through the child (derived class) in the base class.
What is the C++ pattern I am looking for?
class Base
{
// Common behavior, operate on m_object
...
void Foo()
{
m_object.Bar();
}
};
class Derived1 : public Base
{
// No methods, use Base methods
private:
MyObject1 m_object;
}
class Derived2 : public Base
{
// No methods, use Base methods
private:
MyObject2 m_object;
}
The thing that is boxing me into this situation is MyObject1, MyObject2, etc offer Bar(), but don't share a common base class. I really can't fix the derivation because the objects come from an external library.
If they are introduced in the derived classes, then the base class cannot directly access them. How would the base class know that all derived classes have a specific member?
You could use virtual protected methods like so:
class my_base
{
protected:
virtual int get_whatever();
virtual double get_whatever2();
private:
void process()
{
int y = get_whatever();
double x = get_whatever2();
//yay, profit?
}
}
class my_derived_1 : my_base
{
protected:
virtual int get_whatever()
{
return _my_integer;
}
virtual double get_whatever2()
{
return _my_double;
}
}
Another possibility (if you want to call the base methods from the derived classes) is to simply supply the arguments to the base methods.
class my_base
{
protected:
void handle_whatever(int & arg);
};
class my_derived : my_base
{
void do()
{
my_base::handle_whatever(member);
}
int member;
};
C++ does and doesn't. It has a very powerful multiple inheritance support, so there is no super keyword. Why? Imagine that your base class is, say, inherited by another two classes, or even is a part of virtual inheritance hierarchy. In that case you can't really tell what super is supposed to mean. On the other hand, there are virtual methods, you can always have them in base class and implement in derived classes (that's what languages like Java do, except that they they don't have multiple class inheritance support). If you don't want to go with polymorphism, you can use something like this:
#include <cstdio>
template <typename T>
struct Base
{
void foo ()
{
std::printf ("Base::foo\n");
static_cast<T *> (this)->bar ();
}
};
struct Derived : Base<Derived>
{
void bar ()
{
std::printf ("Derived::bar\n");
}
};
int
main ()
{
Derived d;
d.foo ();
}
This is an extremely simple example - you can extend the above example with access control, friends, compile-time assertions etcetera, but you get the idea.
Have you considered not using inheritance?
class FooBar
{
MyObject m_object;
public:
FooBar(MyObject m): m_object(m) {}
//operate on different m_objects all you want
};
What about deriving your six separate objects from a common base class? Then you can declare virtual methods in that base class to create your interface, and then implement them in the derived object classes.
Maybe you just need a template instead of superclass and 6 derived classes?
It seems that you need to access not the parent's, but child's field. You should do it by introducing an abstract method:
class ParentClass
{
public:
void f();
protected:
virtual int getSomething() = 0;
};
ParentClass::f()
{
cout << getSomething() << endl;
}
class DerivedClass : public ParentClass
{
protected:
virtual int getSomething();
}
DerivedClass::getSomething() { return 42; }
If you need to access parent's method, just use ParentClass::method(...):
class ParentClass
{
public:
virtual void f();
};
class DerivedClass : public ParentClass
{
public:
virtual void f();
};
void DerivedClass::f()
{
ParentClass::f();
}
I am trying to figure out an interesting multiple inheritance issue.
The grandparent is an interface class with multiple methods:
class A
{
public:
virtual int foo() = 0;
virtual int bar() = 0;
};
Then there are abstract classes that are partially completing this interface.
class B : public A
{
public:
int foo() { return 0;}
};
class C : public A
{
public:
int bar() { return 1;}
};
The class I want to use inherits from both of the parents and specifies what method should come from where via using directives:
class D : public B, public C
{
public:
using B::foo;
using C::bar;
};
When I try to instantiate a D I get errors for trying to instantiate an abstract class.
int main()
{
D d; //<-- Error cannot instantiate abstract class.
int test = d.foo();
int test2 = d.bar();
return 0;
}
Can someone help me understand the problem and how to best make use of partial implementations?
You don't have diamond inheritance. The B and C base classes of D each have their own A base class subobject because they do not inherit virtually from A.
So, in D, there are really four pure virtual member functions that need to be implemented: the A::foo and A::bar from B and the A::foo and A::bar from C.
You probably want to use virtual inheritance. The class declarations and base class lists would look like so:
class A
class B : public virtual A
class C : public virtual A
class D : public B, public C
If you don't want to use virtual inheritance then you need to override the other two pure virtual functions in D:
class D : public B, public C
{
public:
using B::foo;
using C::bar;
int B::bar() { return 0; }
int C::foo() { return 0; }
};
You need to make your base classes virtual in order for them to inherit properly. The general rule is that all non-private member functions and base classes should be virtual UNLESS you know what you're doing and want to disable normal inheritance for that member/base.