This is a simple question (I think). I'm just not sure about it and I'm looking for a good solution too :)
Let's say I have this:
class Base {
public:
virtual ~Base() {}
virtual Base& connect(Base &b) = 0;
}
class Derived: public Base {
public:
virtual ~Derived() {}
virtual Base& connect(Base &b)
{
// do_something
}
}
// Name is a class that is basically a String and assign it to any A or B object.
class A: public Derived {
public:
A(name N) { ... }
virtual ~A() {}
}
class B: public Derived {
public:
B(name N) { ... }
virtual ~B() {}
A& connect(A &a)
{
// do something else
}
}
int main(int argc, char *argv[])
{
A objA("A");
B objB("B");
// Here's where is my issue
objB.connect(objA);
}
When I call objB.connect(objA), it is actually calling Base& connect(Base &b). I understand because both are child of Base and both have connect() defined in Derived. But the thing is that I would like that whenever I have objB.connect(objA), it should call A& connect(A &a) instead.
I would like to know if there is a way to have it the way I want.
Thanks :)
UPDATE
I edited this, because I had several typos. I didn't copy-paste the code, because it is quite more complex than I wish >.< Hope it is enough.
Your code won't compile. Here is code that compiles and result is as you desire: you can choose which version of connect to call based on a pointer type:
class Base {
public:
virtual ~Base() {}
virtual Base& connect(Base &b) = 0;
};
class Derived: public Base {
public:
virtual ~Derived() {}
virtual Base& connect(Base &b)
{
qDebug() << "Baseconnect";
}
};
class AA: public Derived {
public:
AA() {}
virtual ~AA() {}
};
class BB: public Derived {
public:
BB() {}
virtual ~BB() {}
AA& connect(AA &a)
{
qDebug() << "Aconnect";
}
};
example:
int main(int argc, char *argv[])
{
AA* aaptr = new AA;
BB* bbptr = new BB;
bbptr->connect(*aaptr); // version from BB is called
Derived* dptr = new BB;
dptr->connect(*aaptr); // version from Derived is called
// ...
}
As a side note, please always ensure that your code compiles and question is well defined. You narrow down the chances for helpful answer to your question otherwise.
Related
Is it possible to use covariance alongside virtual inheritance?
Here is a simplified scenario.
class A{};
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};
class CoreA
{
protected:
virtual A& Get() = 0;
};
class CoreB : public virtual CoreA {
virtual B& Get() = 0;
};
class CoreC : public virtual CoreA {
virtual C& Get() = 0;
};
class CoreD : public CoreB, public CoreC
{
public:
virtual D& Get() override { return d; }
protected:
D d;
};
I am running into an ambiguity problem due to both CoreB's and CoreC's Get functions. If they are removed, there are no more errors, but I need those Get functions.
I have been able to resolve the issue by renaming the Get functions inside of CoreB and CoreC, while overriding them in CoreD
class CoreB : public virtual CoreA {
virtual B& Get_B() = 0;
};
class CoreC : public virtual CoreA {
virtual C& Get_C() = 0;
};
class CoreD : public CoreB, public CoreC
{
public:
virtual D& Get_B() override { return d; }
virtual D& Get_C() override { return d; }
virtual D& Get() override { return d; }
protected:
D d;
};
Does anyone know of a cleaner workaround?
Reported Issue to Microsoft under Developer Community
Unfortunately, this is a limitation in MSVC’s object model and requires ABI breaking changes to support.
You can consider writing your own covariant wrapper to work around.
If i have a base class Base:
class Base {
public:
bool foo;
virtual bool bar() = 0;
virtual ~Base() = default;
};
And two derived classes:
class Derived1 : public Base
{
Derived1();
bool bar() override;
}
class Derived2 : public Base
{
Derived2();
std::vector<baz*> bazVector;
bool bar() override;
}
And i have a vector std::vector<Base*> mainVector which us populated like this:
mainVector.push_back(someDerivedPointer)
At some point i need to determine what object is stored: Derived1 or Derived2, so i could access Derived2->bazVector if object is Derived2
One solution is trying to dynamic_cast<Derived2>(mainVector.at(someIndex)) and check for returned nullptr, or storing some enum that would tell me what class this object belongs to, but these solutions seem crutchy, and i wonder if there is a better solution.
As advised in the comment section, you are probably looking the wrong direction.
There's high chance you are not tackling the problem with the right approach.
If you need to write different logic based on the actual derived class from a pointer, you are missing something.
We don't have too much details, but for what you said, you have two options:
1: adding a virtual method to retrieve your vector:
class Base {
public:
bool foo;
virtual bool bar() = 0;
virtual ~Base() = default;
virtual std::vector<baz*> getVector() = 0;
};
class Derived1 : public Base
{
public:
Derived1();
bool bar() override;
virtual std::vector<baz*> getVector() override {return {};};
}
class Derived2 : public Base
{
std::vector<baz*> bazVector;
public:
Derived2();
bool bar() override;
virtual std::vector<baz*> getVector() override {return bazVector;};
}
2: insert the logic where you need this vector into a virtual function (this is probably the better):
class Base {
public:
bool foo;
virtual bool bar() = 0;
virtual ~Base() = default;
virtual void doSomething() = 0;
};
class Derived1 : public Base
{
public:
Derived1();
bool bar() override;
virtual void doSomething() override {/*no op*/};
}
class Derived2 : public Base
{
std::vector<baz*> bazVector;
public:
Derived2();
bool bar() override;
virtual void doSomething() override {/*do something with you bazVector*/};
}
The other answer is most likely the best way to go forward in OP's case, but considering how vague the question's title is, there is an alternative idiom that is sometimes useful when:
All the derived classes of Base are known ahead of time.
The derived classes are particularly heterogenous, and creating a lowest-common-denominator interface would be problematic in some way, shape, or form.
A good example of this would be an AST. clang's ASTConsumer uses a flavor of the technique.
The visitor. The basic idea is to have an external interface with virtual methods for each derived class, and have a single virtual function in Base that dispatches this to the correct function.
class Derived1;
class Derived2;
class Base {
public:
class Visitor {
public:
virtual void operator()(Derived1&) {}
virtual void operator()(Derived2&) {}
protected:
~Visitor() = default;
};
virtual void visit(Visitor& v) = 0;
virtual ~Base() = default;
};
class Derived1 : public Base
{
public:
Derived1(){}
void visit(Base::Visitor& v) override { v(*this); }
};
class Derived2 : public Base
{
public:
Derived2(){}
void visit(Base::Visitor& v) override { v(*this); }
};
// Usage example:
struct MyVisitor final : public Base::Visitor {
void operator()(Derived1& obj) override {
std::cout << "1\n";
}
void operator()(Derived2& obj) override {
std::cout << "2\n";
}
};
int main() {
std::vector<std::unique_ptr<Base>> bases;
bases.push_back(std::make_unique<Derived1>());
bases.push_back(std::make_unique<Derived2>());
MyVisitor v;
for(auto& b : bases) {
b->visit(v);
}
}
I ran into an error yesterday and, while it's easy to get around, I wanted to make sure that I'm understanding C++ right.
I have a base class with a protected member:
class Base
{
protected:
int b;
public:
void DoSomething(const Base& that)
{
b+=that.b;
}
};
This compiles and works just fine. Now I extend Base but still want to use b:
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b+=that.b;
d=0;
}
};
Note that in this case DoSomething is still taking a reference to a Base, not Derived. I would expect that I can still have access to that.b inside of Derived, but I get a cannot access protected member error (MSVC 8.0 - haven't tried gcc yet).
Obviously, adding a public getter on b solved the problem, but I was wondering why I couldn't have access directly to b. I though that when you use public inheritance the protected variables are still visible to the derived class.
A class can only access protected members of instances of this class or a derived class. It cannot access protected members of instances of a parent class or cousin class.
In your case, the Derived class can only access the b protected member of Derived instances, not that of Base instances.
Changing the constructor to take a Derived instance will solve the problem.
protected members can be accessed:
through this pointer
or to the same type protected members even if declared in base
or from friend classes, functions
To solve your case you can use one of last two options.
Accept Derived in Derived::DoSomething or declare Derived friend to Base:
class Derived;
class Base
{
friend class Derived;
protected:
int b;
public:
void DoSomething(const Base& that)
{
b+=that.b;
}
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b+=that.b;
d=0;
}
};
You may also consider public getters in some cases.
As mentioned, it's just the way the language works.
Another solution is to exploit the inheritance and pass to the parent method:
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
Base::DoSomething(that);
d=0;
}
};
You have access to the protected members of Derived, but not those of Base (even if the only reason it's a protected member of Derived is because it's inherited from Base)
You can try with static_cast< const Derived*>(pBase)->Base::protected_member ...
class Base
{
protected:
int b;
public:
...
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b += static_cast<const Derived*>(&that)->Base::b;
d=0;
}
void DoSomething(const Base* that)
{
b += static_cast<const Derived*>(that)->Base::b;
d=0;
}
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething()
{
b+=this->b;
d=0;
}
};
//this will work
Following the hack for stl I wrote a small code which seems to solve the problem of accessing the protected members in derived class
#include <iostream>
class B
{
protected:
int a;
public:
void dosmth()
{
a = 4;
}
void print() {std::cout<<"a="<<a<<std::endl;}
};
class D: private B
{
public:
void dosmth(B &b)
{
b.*&D::a = 5;
}
};
int main(int argc, const char * argv[]) {
B b;
D d;
b.dosmth();
b.print();
d.dosmth(b);
b.print();
return 0;
}
Prints
a=4
a=5
Use this pointer to access protected members
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
this->b+=that.b;
d=0;
}
};
#include <iostream>
class Base
{
public:
virtual ~Base() {}
virtual void f()
{
std::cout << "base\n";
}
};
class Derived : public Base
{
public:
virtual ~Derived() {}
virtual void f()
{
std::cout << "derived\n";
}
};
int main()
{
Derived* D = new Derived;
D->f();
delete D;
return 0;
}
So I am calling Derived::f but I want to call Base::f too. Is there any other way than calling Base::f() inside Derived::f()?
Sounds like what you want is a Non Virtual Interface (NVI) design. This is great when you want customization points (polymorphism, for example) for derived classes, but a somewhat guaranteed call flow.
class Base
{
public:
virtual ~Base() {}
void f()
{
// ... do something that always run before
f_impl();
// ... and after the extension point
}
protected:
virtual void f_impl()
{
}
};
class Derived : public Base
{
protected:
virtual void f_impl() override
{
std::cout << "extended!\n";
}
};
int main()
{
Derived d;
d.f(); // Base can _always_ run things before and after Derived
}
I have a class hierarchy as below:
class Base
{
public:
virtual Base& derived() const=0;
}
class Derived:public Base
{
public:
Derived& derived() const
{
return dynamic_cast<Derived&>(*this);
}
void test(){cout<<"Hi";}
}
The purpose of derived() is to return reference of the exact type.
int main()
{
Derived d;
Base &b = d;
(b.derived()).test();
return 0;
}
I get a compile error
can't find void test() in Base
As I checked, the Derived::derived() did get called. It seems that Derived::derived() didn't return reference to derived class as expected.
Did you just forget the inheritance in your sample? Something like this would work, but it's very poor design.
class Base
{
public:
virtual ~Base() { }
template < typename T>
const T& derived() const {
return dynamic_cast<const T&>(*this);
}
};
class Derived : public Base
{
public:
void test() const {std::cout<<"Hi";}
};
int main(int argc, const char * argv[])
{
Derived d;
const Base& b = d;
b.derived<Derived>().test();
}
Standard override situation. I included a function as well since you said you wanted to pass the value as a parameter.
class Base
{
public:
virtual void test() const { }
};
class Derived : public Base
{
public:
void test() const {std::cout<<"Hi";}
};
void func(const Base& b) {
b.test();
}
int main(int argc, const char * argv[])
{
Derived d;
const Base& b = d;
b.test();
func(b);
}