I have the following code sample:
class A
{
public:
A(int a):AA(a) {};
int AA;
virtual int Test()
{
return AA;
};
};
class B
{
public:
B(int b):BB(b) {};
int BB;
virtual int Test()
{
return BB;
};
};
class C:public A, public B
{
public:
C(int a, int b, int c) :A(a),B(b),CC(c) {};
int CC;
};
int main()
{
A *a = new C(1,2,3);
B *b = new C(1,2,3);
C *c = new C(1,2,3);
int x = a->Test() ; // this is 1
int y = b->Test() ; // this is 2
// int z = c->Test() ; // this does not compile
return 0;
}
I was expecting the calls to a->Test() and b->Test() to be ambiguous too as the object a is a C and therefore inherits from A and B both of whom have identical Test() functions. However, they both call the implementation which corresponds to the delcared type rather than the type that the object actually is.
Can anyone explain why these calls are not ambiguous?
Does C++ always behave this way?
In fact,a C instance is both a full A instance and a full B instance (so holds a copy of A methods & B methods)
Since a is a A* , the compiler will use the A virtual table copy that is inside of the C instance
Since b is a B* , the compiler will use the B virtual table copy that is inside of the C
instance
you cannot use C* since the compiler will not now which Test() method of A or B you want to call (since the C class holds both A::Test & B::Test symbols)
if you implement a C::Test() method, then it will be called both instead of A::Test() & B::Test() since method is virtual for both A & B.
Because A does not know anything about the existence of C.
Consider a slightly different scenario:
foo.h
class A { public: virtual void Test() {} };
void myFunction(A *a);
foo.cpp
#include "foo.h"
void myFunction(A *a) {
a->Test();
}
You would expect this to compile, I guess? But what if I later independently inherited from A, should that affect whether this code compiles?
Related
I wonder what is the proper way to assign/override a method from that of another class. For example, here below classes A and B are not and should not be subclassed, but method "A.foo" is a prototype and should be assinged/set in the initialization of B. That is, "A.foo = B.bar_b" (or C or D etc). (The overall idea is to register a send method of servers (B) with a client (A).)
class A {
public:
virtual void foo(arg argA) {
// empty
};
};
class B {
public:
B(A a) {
a.foo = &B::bar_b;
}
void bar_b(arg argA) {
// do stuff B
};
};
A a;
B b(a);
a.foo(arg) // calls bar_b
It doesn't work that way. There are two ways to answer your question. The first is to use proper overriding:
class A {
public:
virtual void foo() {
// empty
};
};
class B : public A {
public:
void foo() override {
// do stuff B
};
};
B b;
A& b_ref = b;
b_ref.foo(); // calls B::foo
The other way is trying to interpret what you actually want to do. Perhaps you want to swap some implementation at runtime to select what A::foo is actually doing.
You need a B to call a method of the class B. Also B(A a) passes the A by value and the assignment in the constructor wont have any effect on the A you pass. Though, most importantly you cannot dynamically assign member functions. However, you can assign to member variables:
#include <functional>
struct A {
public:
void foo() {
do_foo();
};
std::function<void()> do_foo;
};
class B {
public:
B() = default;
B(A& a) {
a.do_foo = [](){B b; b.bar_b(); };
}
void bar_b() {};
};
I have an abstract class A with the pure virtual method void foo(int a) = 0
Then I have several classes that inherit from A and all of them define the method foo. But I need one of them, B, to make it so foo takes an extra parameter, int b, so sort of an overload.
Then I would like to do this:
A *bInstance = new B();
bInstance -> foo(1, 2);
But I get an error telling me that foo is taking too many parameters.
Writing this, I realize it's kind of a weird thing to do so maybe you can't do this and it's good that you can't do it. But in case it is possible, please do tell me how I should go about it.
You can use the overloaded function of B only if the pointer to use is of type B.
See:
#include <iostream>
#include <memory>
class A{
public:
virtual void foo(int a) = 0;
};
class B : public A
{
public:
virtual void foo(int a) override
{
}
void foo(int a, int b)
{
std::cout << a << "," << b;
}
};
int main(){
auto b = std::make_shared<B>();
b->foo(1, 2);
//to use a:
A* aPtr = b.get();
aPtr->foo(1);
return 0;
}
Although Bernd's answer is a possiblility, you must ask yourself what the effect of an overload is. E.g., think of the following.
std::unique_ptr<A> bAsA = std::make_unique<B>();
bAsA->foo(1, 2); // no worky.
bAsA->foo(1); // works, but what should it do?
It there's a different interface between A and B, I would suggest to add a layer of abstraction in form of a new base class (which I will call C).
So instead of
struct A {
// common
virtual void bar() {}
// class specific
virtual void foo(int) = 0;
};
struct B: public A {
// weird unused override which is still available
void foo(int) override {}
// class specific
void foo(int, int) {}
};
use
struct C {
// common
virtual void bar() {}
};
struct A: public C {
// class specific
virtual void foo(int) = 0;
};
struct B: public C {
// class specific
void foo(int, int) {}
};
You can fully achieve want you want using a default parameter:
class A
{
public:
virtual void foo(int a, int b = 0) = 0;
virtual ~A() = default;
};
class B : public A
{
public:
void foo(int a, int b) override { }
};
class C : public A
{
public:
void foo(int a, int b = 0) override { }
};
int main()
{
A* b = new B();
A* c = new C();
b->foo(1, 2);
c->foo(1);
}
You don't have to use this parameter in C::foo implementation (and any other derived classes) if you don't need to.
I'm working on an assignment involving 4 classes and diamond inheritance. I've based all my answers on an assumption that may or may not be correct.
The diamond hierarchy is like this:
A
/ \
B C
\ /
D
and the code looks like this:
class A
{
private:
string s;
public:
A(string s);
virtual ~A;
virtual void set(string s);
virtual string get();
};
class B : public virtual A
{
public:
void set(string s);
string get();
}
class C : public virtual A
{
public:
void set(string s);
}
class D : public B, public C
{
public:
void set(string s);
}
Suppose I have a pointer that looks like this:C *obj = new D();
If get is called on obj, the pointer will actually end up looping back to D and then invoke B's get method. A C object alone would end up invoking A's get method. Assuming B and A's get methods return different results, which result would be expected?
The code you provided unfortunately won't compile as is.
We can create a similar example and just try it:
#include <cstdio>
struct A
{
virtual char const * get() {return "a";};
virtual ~A() = default;
};
struct B : public virtual A
{
char const * get() override {return "b";};
};
struct C : public virtual A
{
//char const * get() override {return "c";};
};
struct D : public B, public C
{
//char const * get() override {return "d";};
};
int main()
{
A* a = new A();
B* b = new B();
C* c = new C();
C* d = new D();
printf("%s\n", a->get());
printf("%s\n", b->get());
printf("%s\n", c->get());
printf("%s\n", d->get());
delete a;
delete b;
delete c;
delete d;
}
which gives:
a
b
a
b
isocpp calls this delegating to a sister class
As B and C both virtually inherit A, there is only a single instance of A, therefore in the virtual table, when B overrides an implementation of A, only a single member overrides get and this becomes also overridden for D.
Should you also uncomment the the get method in C, then we would get:
virtual.cc:19:8: error: no unique final overrider for 'virtual const char* A::get()' in 'D'
19 | struct D : public B, public C
|
However, further modifying the example and also uncommenting the get in D would make the code compile again. Now returning:
a
b
c
d
It will act like a D object.
Just like with single inheritance, it acts like the class that was created (not what the pointer to it is).
I'm fairly new to object-oriented program, so maybe this is a basic question, but I'd appreciate any help you can offer.
If I have a class B, which is derived from class A, is there some way for objects of class B to access class B's member functions from within member functions of class A? So in the example below I might have a call to function2 from within function1 if the object initially calling function1 is of type B. Is this possible, and if so, how do I accomplish it? Thanks!
class A
{
public:
int a;
int b;
A(){}
A(int a, int b) { this->a = a; this->b = b; }
int function1();// { call function2 if class B }
};
class B : public A
{
public:
int c;
int d;
B(){}
B(int c, int d) { this->c = c; this->d = d; }
int function2();
};
A function inside A doesn't have any idea of the fact that a class B which extends A exists and which methods it has.
To be able to invoke a specific method implemented in B from A you need to declare it in A as virtual, possibly pure virtual (= 0).
class A {
protected:
virtual void function2() = 0;
public:
void function1() { this->function2(); }
}
class B : public A {
protected:
void function2() override { ... }
}
A virtual method is resolved at runtime, this means that when invoked, the more specific implementation for the object on which it is called is executed. A pure virtual method doesn't have any base implementation, this makes A abstract and forbids its instantiation.
EDIT: a final note, don't call virtual methods from base constructors or destructors. It is dangerous and a bad practice, not that this is your case but you never know.
Yes. You need to define function2() as a virtual function in class A. Then calling it from function1 will result in B's function2() being called if the object is actually a B. For example:
class A
{
public:
int a;
int b;
A(){}
A(int a, int b) { this->a = a; this->b = b; }
int function1() { return this->function2(); }
virtual int function2() { return 0; }
};
class B : public A
{
public:
int c;
int d;
B(){}
B(int c, int d) { this->c = c; this->d = d; }
int function2() override { return 999; }
};
If there is no sensible implementation of function2 for A, then it would never make sense to have an A object. You can express this by declaring function2 to be pure virtual; e.g.
virtual int function2() = 0;
virtual allows you to override function in parent class.
class A
{
public:
A(){}
A(int a, int b):a(a), b(b) {}
int function1() { return this->function2(); }
virtual int function2() { //what function2 in parent class should do }
private:
int a;
int b;
};
class B : public A
{
public:
B(){}
B(int c, int d):c(c), d(d) {}
int function2() { //what function2 in child class should do }
private:
int c;
int d;
};
to create an instance of another class from a class even if the class I want to have an instance of is declared next of the class I am creating an instance from. Just like in C# and Java.
Thank you
You can use a forward declaration for some purposes, but you will need to have the complete type whenever you actually make use of it. It could be advisable to make the question more specific as to what you really want to achieve, as there might be simpler approaches to your problem (if order is important it might indicate a circular dependency between classes A and B, and that is not usually good).
class B;
class A
{
public:
A( B b, B* bp, B& br ) : bp_(bp), br_(br) {} // ok, incomplete types can be used as argument types
B f()
// { return B(); } // nok: cannot create objects of incomplete type
;
B* f2() { return bp_; } // ok
B& f3() { return br_; }; // ok
void g()
// { bp_->g(); br_.g(); } // nok: cannot call methods of an incomplete type
;
void g( B const & b )
// { b.g(); } // nok: cannot call methods of an incomplete type
private:
B * bp_; // ok (also const version)
B & br_; // ok (also const version)
// B b_; // nok: B must be a complete type here
};
class B { // A is complete, any use is correct here
void g() {}
};
// From here on, B is a complete type and can be used in any possible way
B A::f() {
return B(); // ok, now B is complete
}
void A::g() {
br_.g(); // ok, B is complete here
bp_->g(); // ok, B is complete here
}
void A::g( B const & b ) {
b.g();
}
Sure. You just need a forward declaration. Something like this works just fine:
#include <iostream>
class B;
class A {
public:
void hello( B &b );
void meow();
};
class B {
public:
void hello( A &a );
void woof();
};
void A::hello( B &b ) { b.woof(); }
void A::meow() { std::cout << "Meow!" << std::endl; }
void B::hello( A &a ) { a.meow(); }
void B::woof() { std::cout << "Woof!" << std::endl; }
int main() { A a; B b; a.hello( b ); b.hello( a ); return 0; }
The key here is that you can only use pointers or references to a class until it has been fully defined. So in the example I gave, the hello() method in A can be declared to take a reference to B, even though we haven't defined B at the point. After the definition of B, however, the definition of the method A::hello() is free to use B as it pleases.
I guess you mean to do something like this:
class B; //Forward declaration
class A
{
private:
B b;
};
class B
{
};
This is not possible in C++ as the compiler needs to know the sizeof(B) when compiling class A.
As a solution what you can do is:
class B; //Forward declaration
class A
{
public:
A();
~A();
private:
B* m_pB; //Store a pointer to B
};
class B
{
};
A::A()
{
m_pB = new B; //Create an instance of B
}
A::~A()
{
delete m_pB; //Explictly deallocate the memory.
m_pB = NULL;
}
Once you forward declare B in the header you can use it in the .cpp file without trouble to access public variables and methods.