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!
Related
I'm working on a small project, and I found myself in a situation like this :
class A{}
class B : class A {
public:
void f();
int getType() const;
private:
int type;
}
class C : class A{
public:
int getType() const;
private:
int type;
}
I want to know if there's a way to call the f() function (in class B) from an object of type A?
I tried this but it says function f() cannot be found in class A :
int main(){
vector<A*> v;
// v initialized with values of A ...
if (v->getType() == 1){ // 1 is the type of B
v->f();
}
}
As you've seen, this code won't compile because A doesn't have an f method. In order to make it work, you'd have to explicitly downcast the pointer:
B* tmp = dynamic_cast<B*>(v);
tmp->f();
To begin with, with your current classes, you can't call getType() on an A*. Because the interface of A doesn't have this method. To solve this problem, you either need to make getType a virtual function in A, or move the type field to base class A (as protected) and initialize it in the constructors of the child classes. Let me show you the first method, because I think it is a better approach, since it makes the objective of this function more clear.
class A {
public:
virtual int getType() { return 0; } // or delete the function: ... getType() = 0;
}
class B : public A {
public:
int getType() override { return 1; }
}
With these classes, once you create an instance of B, getType() returns 1 when called on that instance, whether it is pointed to by an A* or B*:
A *object = new B();
object->getType(); // returns 1
Now, if you need to access the f() from B, you can again add it as a virtual method to A's interface, or make a cast to B*.
Using a virtual method:
class A {
public:
virtual void f() { /* a default action maybe? */ }
}
class B : public A {
public:
void f() /* override if you want */ { /* whatever this function does in B */ }
}
...
for (A *ptr : v)
ptr->f();
Using a cast:
class A {
public:
virtual int getType() { return 0; }
}
class B : public A {
public:
void f();
int getType() override { return 1; }
}
...
for (A *ptr : v)
if (ptr->getType() == 1)
dynamic_cast<B*>(ptr)->f();
class Builder
{
public:
virtual void Build(int a) = 0;
};
class ConcreteBuilder1 : public Builder
{
public:
void Build(int a);
};
class ConcreteBuilder2 : public Builder
{
public:
void Build(int a. struct A* a);
};
So My question is how to design Build() method to take both parameters(int, struct* A). But with same builder interface ?
So that,
int x;
struct A* y;
Builder concrteBuilder1 = new ConcreteBuilder1();
concrteBuilder1 ->Build() // // Here I am forced to pass struct A* a eventhough not needed for concerte builder1 . And I am also forced to forced to change Builder interface too.
My apologies if I did not convey the question clearly.
Builder usually builds an object of another class. You may try something similar to this:
class ToBuild
{
//some code here
};
class Builder
{
public:
virtual ToBuild * build() = 0;
};
class ConcreteBuilder : public Builder
{
int _valA;
int _valB;
public:
ToBuild * build() override
{
ToBuild * obj = new ToBuild();
//initalize obj using _valA and _valB variables;
return obj;
}
ConcreteBuilder& valA(const int val)
{
_valA = val;
return *this;
}
ConcreteBuilder& valB(const int val)
{
_valB = val;
return *this;
}
};
int main()
{
ConcreteBuilder b;
ToBuild * obj = b.valA(1).valB(2).build();
//some code
delete obj;
return 0;
}
[edit]
You can write another derived class with as many parameters as you want and still use a single 'build' method.
Add
using Builder::Build;
to the derived class's declarations. This will import this symbol into the derived class, and make both it, and the derived class methods, of the same name, available to overload resolution. I.e.
using Builder::Build;
void Build(int a);
I'm ignoring the fact that you can't construct the derived class anyway, since it fails to implement this pure virtual function from the base class.
Derived class override their functions from the one which has same parameters and same return value.
So if you declare a function like...
class Builder
{
public:
virtual void Build() = 0;
};
class ConcreteBuilder1 : public Builder
{
public:
void Build(int a);
};
class ConcreteBuilder2 : public Builder
{
public:
void Build(int a. struct A* a);
};
Here, Build function in ConcreteBuilder1 class treated as a new function, not override function.
So try this.
class Builder
{
public:
virtual void Build(int a, A* b = 0) = 0;
};
class ConcreteBuilder1 : public Builder
{
public:
void Build(int a);
};
class ConcreteBuilder2 : public Builder
{
public:
void Build(int a, struct A* a);
};
I wish it's helpful for you.
So I was wondering if it is possible in C++ to call a parent class method that uses an overridden method without using the parent version of the overridden method. (I know this is unclear so I made an example!)
For example, below I would like to call class A's version of findPath() from an object of class B, while using the addPoint method that is defined by class B. Currently, if I call findPath() from an object of class B, it uses the addPoint method defined in class A.
Actual Output:
A.findPath(), path = {1,2,3,4,5,6,7,8,9,10)
B.findPath(), path = {1,2,3,4,5,6,7,8,9,10)
Desired Output:
A.findPath(), path = {1,2,3,4,5,6,7,8,9,10}
B.findPath(), path = {2,4,9,16,25,36,49,64,81,100}
class A
{
public:
vector<int> path;
void addPoint(int num) {
path.push_back(num);
}
vector<int> findPath() {
for (int i = 0; i < 10; i++) {
addPoint(i);
}
}
};
class B : public A
{
public:
void addPoint(int num) {
path.push_back(num*num);
}
};
At the moment, I am copying and pasting findPath into class B to get the desired output, but I feel like there should be an easier way. Thanks!
You need to use virtual in the base class. You should also add override in the derived class, compare the CppCoreGuidelines.
class A
{
public:
...
virtual void addPoint(int num) {
path.push_back(num);
}
...
};
class B : public A
{
public:
void addPoint(int num) override {
path.push_back(num*num);
}
};
It is possible. This is known as the Template Method Pattern. The name is a bit unfortunate, because it has nothing to do with C++ templates. A base class can implement something and derived classes only override the individual steps of the bigger "something".
For example:
struct Base {
virtual void stepA() = 0;
virtual void stepB() = 0;
virtual void stepC() = 0;
void do_something_complicated() {
stepA();
stepB();
stepC();
}
};
Derived classes only override the methods for the individual steps, while they are composed in the base class already.
In your example you forgot to declare addPoint as virtual, A should have a virtual destructor and using override is recommended to let the compiler help you in case of mistakes:
class A
{
public:
vector<int> path;
virtual void addPoint(int num) {
path.push_back(num);
}
vector<int> findPath() { // () was missing
for (int i = 0; i < 10; i++) {
addPoint(i);
}
return path; // return was missing
}
virtual ~A() = default;
};
class B : public A
{
public:
void addPoint(int num) override {
path.push_back(num*num);
}
};
I've got an interface A which is publicly available, and a back-end implementation class C, like so:
struct A
{
virtual void f() = 0;
};
struct C : public A
{
virtual void f() override
{
}
};
I would like to gradually migrate to a new interface, B. B will have the same methods, however, the return types might be different. I would like my implemetation class to implement both A and B so that legacy code can keep using A until it is migrated, but new code can be written with B. I know that if I have two pure virtual methods with exactly the same signature, I only need one override in my implementation class. But if they differ by return type, I don't know how to do it...
struct A
{
virtual void f() = 0;
};
struct B
{
virtual int f() = 0;
};
struct C : public A, public B
{
// How do I implement both versions of f() here??
};
The way I would do it is
struct A {}
struct B {}
struct OldImpl : public A {}
struct NewImpl : public B {}
struct Combined : public AImpl, public BImpl {}
You can then pass the combined into anything that wants an A or a B.
The problem with this is that your OldImpl and NewImpl are completely separate. They're not allowed to interact with each other; meaning you can't call setFoo() in A and get the same value in getFoo() in B. Which is probably not what you want from what you described.
To resolve this, don't create a 2nd interface. It wouldn't work anyway because where a xxx() might be void now, and an int later, you probably want to do something with the return value. If you really want to do it in baby steps, create a branch, change a single functions return value, test it, merge it in, repeat.
Thanks for the good responses! But I did figure out my own solution: good old optional parameters!
struct A
{
virtual void f() = 0;
};
struct B
{
virtual int f(int ignoreMe = 0) = 0;
};
struct C : public A, public B
{
virtual void f() override {}
virtual int f(int) override {}
};
No ambiguity for external users using A or B, and no parameters need to change. No ambiguity internally either because parameter is non-optional in the implementation class. The optional parameter can be removed, along with A, once migration is complete.
This at least compiles with VS2017:
struct A
{
virtual void f() = 0;
};
struct A2: public A
{
void f() { Af(); }
virtual void Af() = 0;
};
struct B
{
virtual int f() = 0;
};
struct B2 : public B
{
int f() { return Bf(); }
virtual int Bf() = 0;
};
struct C : public A2, public B2
{
void Af() {}
int Bf() { return 42; }
};
Edit: Could not add this a comment on Paul Accisano's own answer, so I put it here.
Modifying Paul's answer slightly. By making the unused default parameter a protected class, you still have correct type checking, and avoid the potential for a type conflict with another member function.
struct A
{
virtual void f() = 0;
};
struct B
{
protected:
class disambiguator {};
public:
virtual int f(disambiguator ignoreMe = disambiguator()) = 0;
};
struct C : public A, public B
{
virtual void f() override {}
virtual int f(disambiguator ignoreMe) override { return 42; }
};
A *createA() { return new C; }
B *createB() { return new C; }
One application for this could be the gradual migration from raw pointers to smart pointers.
look at following code:
class A
{
public:
virtual int getN() = 0;
};
class B : public A
{
private:
int n = 2;
public:
int getN() { return n; }
};
class C : public A
{
// do not contain property n, it nolonger need getN();
};
class A is a abstract class. Now I have class C derived from A. But it dose not like class B has a property n. So I can't overload getN(), and then class C is a abstract class, which I cannot instantiate it.
So if I want instantiate class C, what should I do?
Inheritance represents a "kind-of" relationship.
Since C does not have a getN() method, it cannot be a "kind of" A since anyone holding a reference to an A has the right to expect getN() to be present.
They have this right because you asserted it by putting getN in the public virtual interface of A.
Moral of the story - avoid inheritance if you can. Prefer encapsulation.
You can try to split A into separate interfaces, which allows sub classes to pick and choose which properties of A they wish to inherit.
Take this, for example:
class A
{
public:
virtual int getN() = 0;
};
class A1
{
public:
virtual int getNum() = 0;
};
class B : public A, public A1
{
private:
int n = 2;
public:
int getN() override { return n; }
int getNum() override { return 42; }
};
class C : public A1
{
public:
virtual int getNum() override { return 1; }
};
Here, C no longer needs getN() so it inherits only from the interfaces that it needs. This pattern is commonly referred to as the interface segregation principle.