I have a base class B and 2 derived classes D1, D2.
class B {
int commonFunc();
virtual int specifyFunc();
}
class D1 : public B {
int specifyFunc();
}
class D2 : public B {
int specifyFunc();
}
Now I meet a requirement that i need to extend my base class function commonFunc(). Since i don't want to modify existing code in base class, i derived another class like:
class B {
virtual int commonFunc(); // Change to virtual
virtual int specifyFunc();
}
class B2 : public B {
int commonFunc(); // A new commonFunc() to meet new requirement
}
However, D1 and D2 cannot use the new commonFunc() in B2 except I modify the inheritance hierarchy.
Here is a possible solution i figured out
class B {
virtual int commonFunc();
virtual int specifyFunc();
}
class D1 : public B {
int specifyFunc();
}
class D2 : public B {
int specifyFunc();
}
class NewD1 : public D1 {
int commonFunc(); // Overrided commonFunc() in base class
}
class NewD2 : public D2 {
int commonFunc(); // Overrided commonFunc() in base class
}
Since the commonFunc() in NewD1 and NewD2 are exactly the same, this solution involves a poor code-copy
I am looking for any design pattern or solution which can dynamically extend base class without much modification to existing class.
You have several solutions. Inheritance should only be used to factorize code for classes having the same responsability. This means that your class Car shouldn't inherit from a class Logger because you want some logging capabilities. This will determine which solution to choose.
1. D1 and D2 have the same responsability than B
Then a good way to have a more modular inheritance is the pattern decorator. This would allow you to do what you want. Just a little code to have an idea:
class B {
virtual int commonFunc();
virtual int specifyFunc();
}
class BDecorator: public B {
B parent;
B(B&);
virtual int commonFunc(); // Implementation forward to parent.
virtual int specifyFunc(); // Implementation forward to parent.
}
class B2: public BDecorator {
int commonFunc();
int specifyFunc();
}
class D1 : public BDecorator {
int specifyFunc();
}
class D2 : public BDecorator {
int specifyFunc();
}
// Use:
B b();
B2 b2(b);
D1 d1(b2);
2. D1 and D2 have not the same responsability than B
Then you should use composition instead of inheritance. This means that you should define a pure abstract class D (an interface) and make D1 and D2 inherit from it. Then, in the constructor of B, you can inject a D. (Yes in this solution, you have to change B a little, tell me if this is really a problem.)
class B {
D d;
int commonFunc();
virtual int specifyFunc(); // Do something with d.
B(D);
}
class D {
virtual int func();
}
class D1 : public D {
int func();
}
class D2 : public D {
int func();
}
// Use with B, but you can use B2 (inheriting from B) instead:
D1 d1();
B b1(d1);
D2 d2();
B b2(d2);
I apologize for my old C++.
Interface Design (Program to an interface, not an implementation)
You could avoid such implementation dependencies by using a common interface (pure abstract class) IB.
You could change behavior (commonFunc())
by adding new classes (NewB) without changing existing classes.
Clients refer to the common interface and are independent of an implementation.
Decorator Design
If you can't do that or really want do extend the behavior of an object dynamically
at run-time, Decorator may help.
But Decorator can only add behavior before and/or after performing the old behavior.
See the following UML diagrams (if you aren't sure how to implement, please let me know).
For further discussion see the GoF Design Patterns Memory for learning
object-oriented design & programming / Decorator / Design Principles (Interface Design)
at http://w3sdesign.com.
Related
Problem
I am looking for the best way to define the variables in parent-child classes, in order to be called by a pointer to their parent class.
This is the protocode:
class Base {
public:
virtual void function() = 0;
};
class A : public Base {
public:
int a, b;
A(int a_, int b_) : a(a_), b(b_) {};
void function() { // do something.. }
};
class B : public Base {
public:
int a, b;
B(int a_, int b_) : a(a_), b(b_) {};
void function() { // do something.. }
};
Base* elements[2] = {
new A(1,2),
new B(3,4)
};
Since I define a, b in both constructors, I might define them in the abstract class Base. This way the code should be more efficient and clean. Is this practice correct? How should I define them?
Possible solutions
The solution I have in mind is implementing a function that returns for example a like this:
class Base {
public:
virtual int return_a() = 0;
};
class A : public Base {
public:
int a, b;
A(int a_, int b_) : a(a_), b(b_) {};
int return_a() {
return a;
}
};
int main(){
int a = elements[0]->return_a();
}
This works, but I am sure it is not an efficient way. Is it better to define a, b in the abstract class? Thanks
Is this practice correct?
I think this is turning into an opinion-based question-answer. If all your derived classes must include the members a and b, then in my opinion, they should be part of the base class. This way, you are guaranteed that all your derived classes will include the members a and b and you (or someone else) won't run the risk of forgetting to include them. Furthermore, by including the members in the base class, you save memory by not having to include them at every single derived class. C++'s virtual provides you with all the necessary tools to accomplish polymorphism, which is what happens when you create an array of Base *.
I would also recommend you use the keyword override for the virtual functions that are overridden in the derived class, and the keyword final for the derived classes that are not meant to become base classes. You can read the benefits of using those keywords from Scott Meyers Modern C++ book.
struct Base
{
int a, b;
Base(int a_, int b_) : a(a_) , b(b_)
{;}
virtual void function() = 0;
};
struct A : Base // A can be a base class of another class.
{
A(int a_, int b_) : Base(a_,b_)
{;}
void funtion() // this will compile, but it's not going to override the Base::function()
{;}
};
struct B final : Base // B can never become a base class.
{
B(int a_, int b_) : Base(a_,b_)
{;}
void funtion() override // this won't compile because override will see that we mis-spelled function()
{;}
};
However, there is no C++ rule that prohibits you from including the members in all of your derived classes.
Also, if all your members are public, then you can use a struct to avoid having to type public inside the classes and in the inheritance method.
struct Base
{
// all members are public
};
struct Derived : Base // public inheritance by default.
{
// all members are public
};
This is somewhat opinion based, but here is what I think based on the code you have posted.
Since you have made Base (from which all classes are derived) an abstract class, it appears that you want to use it as an interface.
In that case, it is better to distinguish between interface inheritance and implementation inheritance. Let Base not have any data which means that it would not require any constructors.
This is one of the coding guidelines given by Bjarne Stroustrup titled: When designing a class hierarchy, distinguish between implementation inheritance and interface inheritance.
The reason given is:
Implementation details in an interface make the interface brittle; that is, make its users vulnerable to having to recompile after changes in the implementation. Data in a base class increases the complexity of implementing the base and can lead to replication of code.
Note that you do not need getters or setters if the data in derived classes is public.
I know that it is not possible to have an instance of an abstract class as a base member of another class, i.e.,
#include <iostream>
class Base {
public:
Base() {};
virtual ~Base() {};
virtual int yield() = 0;
};
class C1: public Base {
public:
C1(): Base() {};
virtual ~C1() {};
virtual int yield() {return 1;};
};
class D {
public:
D(Base & b): b_(b) {};
virtual ~D() {};
private:
Base b_;
}
int main() {
C1 c;
D d(c);
}
will fail to compile with the error
test.cpp:22:10: error: cannot declare field ‘D::b_’ to be of abstract type ‘Base’
The obvious workaround is to use (shared) pointers instead. This, however, makes main somewhat more complicated to read,
int main() {
auto c = std::make_shared<C1>();
D d(c);
}
which I would really like to avoid.
Is there a way to keep the main file as simple as in the above example and still achieve the desired functionality?
You can't. When you are creating D it allocates (in heap or in stack) memory for B. And C1 class needs size of base class B plus size of extra variables/etc in C1 itself even if there are nothing new.
So, use pointers instead.
The error caused by virtual int yield() = 0;. If you use virtual int yield(), it will works. When you used virtual int yield() = 0;, it said that the function is a pure virtual function, so you must override it. So you should give its inheritance class and use the instance of inheritance class in class C1. In a world, virtual int yield() = 0; only remind you that it is only a interface, you must override it. I hope this can help you.
Since Base is an abstract class (has at least one pure virtual function), it can't be instantiated directly.
When you declare D's class member as "Base b_", you are effectively trying to create an instance. You can instead use a pointer there (or some kind of safe/smart pointer).
#include <iostream>
class Base {
public:
Base() {};
virtual ~Base() {};
virtual int yield() = 0;
};
class C1: public Base {
public:
C1(): Base() {};
virtual ~C1() {};
virtual int yield() {return 1;};
};
class D {
public:
D(Base * b): b_(b) {};
virtual ~D() {};
private:
Base *b_; // Use a pointer or safe ptr or something of that sort.
}
int main() {
C1 c;
D d(&c);
}
No. One of the properties of an abstract class is that it cannot be instantiated. That means an instance of an abstract class cannot be a member of another class.
Even if Base was not abstract, your class D's constructor would be slicing the object passed. If passed an instance of C1, the copying (in the initialiser list of D's constructor) would not magically cause an instance of D to contain an object of type C. It would instead create a copy only of the Base part of that object.
In short, your design is broken, and will not work even if - syntactically - it would be possible to simplify the code in main().
I have the following code snippet, and I want to know that which path do c++ compiler choses to inherit the member.
class B
{
public:
void display()
{
cout << "B";
}
};
class B1 : virtual public B
{
};
class B2 : virtual public B
{
};
class C : public B1, public B2
{
};
int main()
{
C c;
c.display();
getchar();
return 0;
}
Is it really possible to have the path chosen by the compiler and if there is then please tell. Might be a basic question but please take some time for it. Thanks in advance.
It's not chosen by the compiler, it's defined by the language. B is virtual, so C has exactly one B base class. Its base classes will be constructed in the order B, B1, B2.
Here are my classes:
class Base1
{
public:
Base1();
~Base1();
virtual void main_func()=0;
}
class D1 : public Base1
{
public:
D1();
~D1();
virtual void main_func(do_d1_main(););
}
class D2 : public Base1
{
public:
D2();
~D2();
virtual void main_func(){do_d2_main();};
}
class Base2
{
public:
Base2();
~Base2();
int m_needed_by_b1;
}
class D12B2: public Base2, public D1, public D2
{
public:
D12B2();
~D12B2();
}
Here's the problem:
Both do_main_func1() and do_main_func2() need access to member m_needed_by_b1 in Base2. How?
Could I define the virtual function main_func for each within class D12B2? That would give them access to all of D12B2, including Base2. How would I specify each separately?
I thought about adding a (protected) member in Base1, that is a pointer to a Base2 object. That would have to be set by D12B2. It seems like there might be a more elegant way to do this.
TIA
ken
It seems like there might be a more elegant way to do this.
More than likely, there is - don't use multiple inheritance.
However, if you are going to insist on using multiple inheritance, there are some things you must note: D1 and D2 should be inherited virtually in D12B2 to avoid the diamond problem. Assuming do_d1_main and do_d2_main actually means main_func, then you can implement a D12B2::main_func that will be able to access m_needed_by_b1.
But back to the original note:
It sounds like Base1 and Base2 should not exist, and D1 and D2 should be pure abstract classes. Which would leave you with
class D1
{
public:
virtual void d1_func() = 0;
};
class D2
{
public:
virtual void d2_func() = 0;
};
class D12B2 : public virtual D1, public virtual D2
{
public:
D12B2();
~D12B2();
virtual void d1_func()
{
// do something
}
virtual void d2_func()
{
// do something else
}
private:
int m_myData;
};
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.