If I want to use inheritance to avoid repeating the common_method method below
int A::different_method()
{ return 1; }
int A::common_method()
{ return this->different_method()+1; }
int B::different_method()
{ return 2; }
int B::common_method()
{ return this->different_method()+1; }
what is the best way to do it?
One way is to make A and B inherit from a base class C, with the new methods:
int A::different_method()
{ return 1; }
int B::different_method()
{ return 2; }
int C::different_method()
{ return 0; }
int C::common_method()
{ return this->different_method()+1; }
but it is a little bit annoying that I have to also define the useless C::different_method. What is the best practice for such situations?
Try using pure virtual function:
struct Base {
virtual int different_method() = 0;
int common_method() {
return different_method() + 1;
}
};
struct Derived1 : Base {
int different_method() override {
return 1;
}
};
struct Derived2 : Base {
int different_method() override {
return 2;
}
};
Check it out live
One way is to make A and B inherit from a base class C,
Yes, you would need a base class C
class C {
public:
virtual ~C() { }
virtual int different_method() = 0;
virtual int C::common_method() {
return this->different_method()+1;
}
}
class A: public C {
// Implement
int different_method() override;
};
class B: public C {
int different_method() override;
};
If you just need to use the class A and B, you can declare your C class as abstract and implement only the common_method(). The different_method() can be declared in header file of C class as pure virtual function in this way:
virtual different_method()=0
I leave you a useful link for the pure virtual function and the abstract class
Are you really tied to the A a; a.common_method() syntax?
Why not
template <typename T>
int common_free_function(T& t) {
return t.different_method() + 1;
}
A a;
B b;
common_free_function(a);
common_free_function(b);
Related
I am grappling with a problem on mocking using gmock. The simplified example below depicts it. I have public member functions in a class, that neither return any values nor take anything as inputs. They only change some private variables in the class. There is a third method that uses the effects of those 2 methods in order to calculate something (say, p) before spitting out the result to the outside world. I need to know how to mock update_a() and update_b() properly. To some extent I can mock them. But I just do not know how to associate some "actions" with their mock versions so that by invoking them I can generate some effects on the private variables. Here is what I have so far:
class MyClass {
private:
int a,
int b,
int p;
public:
MyClass() : a{}, b{}, p{} {}
void update_a() {
a += 2;
}
void update_b() {
b += 5;
}
int calculate_p() {
update_a();
update_b();
p = a * 100 + b * 50; // Just some random math making use of a and b.
return p;
}
}
class MockMyClass :public MyClass {
public:
MOCK_METHOD(void, update_a, (), (override));
MOCK_METHOD(void, update_b, (), (override));
int deletegate_to_real() {
return MyClass::calculate_p();
}
}
TEST(CalculatingP_Test, otherMemberFunctionsInvoked) {
MockMyClass mockob;
EXPECT_CALL(mockOb, update_a()).Times(1);
EXPECT_CALL(mockOb, update_b()).Times(1);
mockOb.delegate_to_real();
}
The test passes because the test only checks whether the mock versions of update_a() and update_b() are invoked. But, I am unable to get the mocked versions of update_a() and update_b() to do something that could directly modify a and b. Changing the private specifier to protected is one way I could think of. But wouldn't that compromise the design?
You can go further with your DIP:
struct IVarAB
{
virtual ~IVarAB() = default;
virtual void update_a() = 0;
virtual void update_b() = 0;
virtual int get_a() = 0;
virtual int get_b() = 0;
};
class VarAB : public IVarAB
{
int a = 0;
int b = 0;
public:
void update_a() override { a += 2; }
void update_b() override { b += 5; }
int get_a() override { return a; }
int get_b() override { return b; }
};
class MyClass {
private:
std::unique_ptr<IVarAB> varAB;
int p = 0;
public:
MyClass() : MyClass(std::make_unique<VarAB>()){}
explicit MyClass(std::unique_ptr<IVarAB> varAB) : varAB{std::move(varAB)} {}
void update_a() { varAB->update_a(); }
void update_b() { varAB->update_b(); }
int calculate_p() {
update_a();
update_b();
p = varAB->get_a() * 100
+ varAB->get_b() * 50; // Just some random math making use of a and b.
return p;
}
};
Then your mock can define return value for both a and b.
It was decided that I could proceed with replacing "private" with "protected". That solves all my problems.
class MockMyClass :public MyClass {
public:
MOCK_METHOD(void, update_a, (), (override));
MOCK_METHOD(void, update_b, (), (override));
void set_dummy_a(int arg_a) {a = arg_a;}
void set_dummy_b(int arg_b) {b = arg_b;}
int deletegate_to_real() {
return MyClass::calculate_p();
}
}
TEST(CalculatingP_Test, otherMemberFunctionsInvoked) {
MockMyClass mockob;
EXPECT_CALL(mockOb, update_a()).Times(1);
EXPECT_CALL(mockOb, update_b()).Times(1);
mockOb.delegate_to_real();
}
TEST(CalculatingP_Test, shouldCalculateP_basedon_a_and_b) {
MockMyClass mockob;
EXPECT_CALL(mockob, update_a()).WillRepeatedly([&mockob]()
{mockob.set_dummy_a(20000);});
EXPECT_CALL(mockob, update_b()).WillRepeatedly([&mockob]()
{mockob.set_dummy_b(20000);});
int expected {3000000};
EXPECT_EQ(expected, mockob.delegate_to_real());
}
I am very new to c++ so I am trying to get a feeling of how to do things the right way in c++. I am having a class that uses one of two members. which one gets determined at instantiation. It looks something like
main() {
shared_pointer<A> a = make_shared<A>();
if ( checkSomething ) {
a->setB(make_shared<B>());
} else {
a->setC(make_shared<C>());
}
a->doStuff();
class A {
public:
doStuff() {
/*here I want to do something like call
m_b->doStuff() if this pointer is set and m_c->doStuff() if
that pointer is set.*/
}
setB( B* p ) { m_b = p; }
setC( C* p ) { m_c = p; }
B* m_b;
C* m_c;
}
}
B and C are some classes with doStuff() member function
There are many members like doStuff. Ideally I would avoid checking for nullptr in each of them. What is the best/most efficient/fastest way to create a switch between those two members?
Is there a way to use a static pointer so that I have a member
static **int m_switch;
and do something like
m_switch = condition ? &m_b : &m_c;
and call
*m_switch->doStuff();
Does the compiler here also replace the extra pointer hop because it is a static?
Is there any other smart way to do those switches?
Normally, class A would be an interface class, which both B and C would inherit and implement. But it sounds like you cannot do this for whatever reason.
Since you want to emulate this, you can start by making the interface:
class A_interface
{
public:
virtual void doStuff() = 0;
virtual void doThings() = 0;
virtual void doBeDoBeDo() = 0;
};
And then you make a template wrapper:
template< class T >
class A : public A_interface
{
public:
void doStuff() override { target.doStuff(); }
void doThings() override { target.doThings(); }
void doBeDoBeDo() override { target.doBeDoBeDo(); }
private:
T target;
};
This essentially does half of what your own example class A was trying to do, but now you can use a common interface. All you need to do is construct the correct templated version you want:
std::shared_ptr<A_interface> a;
if( checkSomething ) {
a = std::make_shared<A<B>>();
} else {
a = std::make_shared<A<C>>();
}
a->doStuff();
You need to have both members implement a common interface to use them similarly. But in order to do that, you need to define the interface and relay the calls to the B and C classes.
// existing classes
class B
{
public:
void doStuff() { std::cout << "B"; }
};
class C
{
public:
void doStuff() { std::cout << "C"; }
};
// define your interface
class I
{
public:
virtual void doStuff() = 0;
};
// new classes
class D : public B, public I
{
public:
void doStuff() override { B::doStuff(); }
};
class E : public C, public I
{
public:
void doStuff() override { C::doStuff(); }
};
// your A class
class A
{
public:
D* b = nullptr; // now type D
E* c = nullptr; // now type E
// your toggle
I* getActive()
{
if (b)
return b;
else
return c;
}
// simple doStuff() function
void doStuff()
{
getActive()->doStuff();
}
};
int main()
{
A a;
if (true)
a.b = new D; // need to initialize as D
else
a.c = new E; // need to initialize as E
a.doStuff(); // prints B
}
But typing this up made me realize that defining D and E could get really tiresome and against what you're trying to save. However, you can define a template to create them like #paddy has done.
There's no one-size-fits-all solution for your problem. What to use depends on your particular problem. A few possible answers:
Interfaces
Strategy Pattern
Pointers (to hold a function or class which implements doStuff)
An interface is like a contract. Any class which inherits from the interface must implement its members. For instance,
class IDoesStuff
{
public:
virtual ~IDoesStuff() {};
virtual void DoStuff() = 0;
};
Can now be used by other classes:
class Foo : public IDoesStuff
{
public:
virtual void DoStuff()
{
// ....
}
};
class Bar : public IDoesStuff
{
public:
virtual void DoStuff()
{
// ....
}
};
And now, in general, one may do:
Foo foo;
IDoesStuff *stuffDoer= &foo;
stuffDoer->doStuff();
This can be used in your particular use case as follows:
class A
{
IDoesStuff *stuffDoer; // Initialize this at some point.
public:
void doStuff() { stuffDoer->doStuff(); }
};
First you must change your memebr variables m_b and m_c to std::shared_ptr.
Add a member variable of type std::function(void()) to hold the target function you want to call. In your sample it is do_stuf.
In your setter functions you can bind target function to your std::function and in do_stuf just call std::function.
(You need a C++11 compiler)
class B
{
public:
void doStuff()
{
}
};
class C
{
public:
void doStuff()
{
}
};
class A
{
public:
void doStuff()
{
m_target_function();
}
void setB(std::shared_ptr<B> p)
{
m_b = p;
m_target_function = std::bind(&B::doStuff, m_b.get());
}
void setC(std::shared_ptr<C> p)
{
m_c = p;
m_target_function = std::bind(&C::doStuff, m_c.get());
}
std::shared_ptr<B> m_b;
std::shared_ptr<C> m_c;
std::function<void()> m_target_function;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::shared_ptr<A> a = std::make_shared<A>();
bool use_B = false;
if (use_B)
{
a->setB(std::make_shared<B>());
}
else
{
a->setC(std::make_shared<C>());
}
a->doStuff();
}
I have a problem with inheritance in C++. The attached code produces the output "1,1," but I thought the action methods from the classes b and c replace the action method from class a. So I expected the output "2,3,". What do I have to change to get the output "2,3,"?
#include <iostream>
//Class a
class a
{
public:
a();
int action();
};
a::a()
{
}
int a::action()
{
return 1;
}
//Class b
class b : public a
{
public:
b();
int action();
};
b::b()
{
}
int b::action()
{
return 2;
}
//Class c
class c : public a
{
public:
c();
int action();
};
c::c()
{
}
int c::action()
{
return 3;
}
//Main Programm
int main()
{
a arr[2];
arr[0] = b();
arr[1] = c();
for(int i = 0; i<2; i++)
{
std::cout << arr[0].action() << ",";
}
return 0;
}
Action needs to be virtual in the base class, otherwise you can't override it.
You can use the foo() override notation to get a compile-time check as to whether you're really overriding something.
You will have to access the derived type trough a pointer to the base type, otherwise you'll slice and do other nasty things. Also sometimes it's a good idea to also make your destructor virtual.
class Base { };
class Derived : public Base { };
some_container<Base*> baseOrDerived;
Then you can allocate both Base and Derived objects into this container. For example with new, although you probably want to use std::shared_ptr<Base> or std::unique_ptr<Base> instead of Base*.
you can use virtual function to get the output "2,3":
first, you should change void action(); to virtual void action(); in class a;
second, you should use pointer to implement polymorphism;
third, you should change arr[0] to arr[i];
Here is my code:
#include <iostream>
//Class a
class a
{
public:
a();
virtual int action();
};
a::a()
{
}
int a::action()
{
return 1;
}
//Class b
class b : public a
{
public:
b();
int action();
};
b::b()
{
}
int b::action()
{
return 2;
}
//Class c
class c : public a
{
public:
c();
int action();
};
c::c()
{
}
int c::action()
{
return 3;
}
int main(int argc, char *argv[])
{
a *(arr[2]);
arr[0] = new b();
arr[1] = new c();
for(int i = 0; i<2; i++)
{
std::cout << arr[i]->action() << ",";
}
return 0;
}
Here is my output:
I have a set of classes like this:
class A {
public:
int DoIt() {
//common code
}
};
class B : public A {
int DoIt() {
if (A::DoIt() == 1) {
return 1;
}
else {
// do b specific code
}
}
};
class C : public A {
int DoIt() {
if(A::DoIt()==1) {
return 1;
}
else {
// do c specific code
}
}
};
Is there a way I can avoid manually putting this code:
if (A::Doit() == 1) { return 1; } else {
in every class which is derived from A?
Just separate the specific code to another method virtual method.
class A
{
public:
int DoIt() /*final*/
{
// common code
if (return_value == 1)
return 1;
else
return DoIt_specific();
}
private:
virtual int DoIt_specific() = 0;
// ^ or some "A"-specific actions if A cannot be abstract.
};
class B : public A
{
virtual int DoIt_specific() /*override*/
{
// specific code for B
}
};
This is known as the non-virtual interface idiom.
I have a class as follows:
Class A
{
virtual int doSomethingCool() = 0;
};
Class B : public A
{
int doSomethingCool();
};
Now the problem likes , I have a set of classes whcih are dependent on A as interface. I need to change the prototype of the function for one of the derived classes. i.e. i need to pass it a parameter.
Class C: public A
{
int doSomethingCool(int param);
};
Any suggestions how i can achieve this ?
No, you don't need to add it to the base class.
class A
{
public:
virtual int doSomethingCool() = 0 {}
};
class B : public A
{
public:
int doSomethingCool() {return 0;}
};
class C: public A
{
private:
int doSomethingCool(); // hide base class version!
public:
int doSomethingCool(int param) {return param;}
};
You can still call doSomethingCool() if done through a base class pointer:
C c;
//c.doSomethingCool (); // doesn't work, can't access private member
c.doSomethingCool (42);
A &a = c;
a.doSomethingCool ();
//a.doSomethingCool (42); // doesn't work, no member of A has that signature
Add it to the interface and default it to call the existing method. You don't have to do the default but don't make it pure otherwise all derived classes will have to implement. It might be better to leave it undefined or to throw. Depends on what you want to achieve.
class A
{
public:
virtual int doSomethingCool() = 0;
virtual int doSomethingCool(int param) {doSomethingCool()};
};
Make the function doSomethingCool() take the int parameter in A.
class A
{
public:
virtual void doSomethingCool(int param) = 0;
};
There's no problem. You can do it. The only caveat is that it will not be treated as an override of the base class virtual function.
class A
{
public:
virtual void doSomethingCool() = 0;
};
class B : public A
{
public:
void doSomethingCool();
};
class C: Public A
{
public:
void doSomethingCool(int param);
};
int main(){}
So while technically possible, you may really want to relook at the design of your interface class A.
One option may be to provide a default argument to A::doSomethingCool
virtual void doSomethingCool(int = 0) = 0;
This isn't syntactically correct C++.
No you can't change a prototype. How would it be used? What would be the value of the param if the non-parametric version would be called?
I would have introduced another, more specific, interface:
struct A
{
virtual int doSomethingCool() = 0;
};
struct A_specific : A
{
virtual int doSomethingCoolWithThis(int i) = 0;
};
class ConcreteA : public A
{
int doSomethingCool() { return 0; }
};
class ConcreteA_specific : public A_specific
{
int doSomethingCool() { return 0; }
int doSomethingCoolWithThis(int param) { return param; }
};
Then I would program to the correct interface:
int main()
{
const A& a1 = ConcreteA();
const A_specific& a2 = ConcreteA_specific();
a1.doSomethingCool();
a2.doSomethingCool();
a2.doSomethingCoolWithThis(2);
}
Just to give you another idea ;-)
Good luck!