In C++11 it is possible to make a public member of a private base class accessible to the outside (public) with a using declaration. For example
class A {
private:
int i = 2;
public:
void f() { i = 3; }
friend bool operator==(const A& l, const A& r) { return l.i == r.i; }
};
class B : private A {
public:
using A::f;
};
int main() {
B b, b2;
b.f();
}
b.f() is possible because of the using A::f in the definition of B.
Is it possible write a similar declaration which would make the up-cast from B& to A& possible for the friend function operator==(A&, A&), so that b == b2 can be called in main()?
No, only B can internally cast itself to A, and it otherwise is not possible because from a client's perspective B is not an A but rather has an A
Even if you replaced your friend bool operator= with a member function equals:
class A {
private:
int i = 2;
public:
void f() { i = 3; }
bool equals(const A& r){return i == r.i;}
};
class B : private A {
public:
using A::f;
using A::equals;
};
While this compiles, you cannot ever call b.equals(b2) because no implicit conversion is ever possible from a type of B to a type of A from the caller's perspective (due to private inheritance) .
You'll need to provide your own operator== or change your inheritance to public or protected. Here's an example where B declares its own friend bool operator==
class B : private A {
public:
using A::f;
friend bool operator==(const B& l, const B& r)
{
return (static_cast<A>(l) == static_cast<A>(r)) && true;
// "true" is a stand-in for some other condition
}
};
Read more at isocpp
Edit:
If you really want to play games, you will notice that I said no implicit conversion is ever possible, but some explicit conversions are. Because B does technically derive from A you can do pointer casting to make it work, but I don't recommend it:
class A {
private:
int i = 2;
public:
void f() { i = 3; }
bool equals(const A* r){return i == r->i;}
};
class B : private A {
public:
using A::f;
using A::equals;
};
int main() {
B b, b2;
b.f();
(::A*)(&b)->equals((::A*)(&b2));
}
Or you could use pointer casting's ugly cousin, reference casting, if you wish to keep the original operator== syntax
class A {
private:
int i = 2;
public:
void f() { i = 3; }
friend bool operator==(const A& l, const A& r) { return l.i == r.i; }
};
class B : private A {
public:
using A::f;
};
int main() {
B b, b2;
b.f();
((::A&)(b)) == ((::A&)(b2));
}
See ยง11.2 [class.access.base] for more
Related
Say i have this part of code:
#include<iostream>
using namespace std;
class A {
public:
virtual int f(const A& other) const { return 1; }
};
class B : public A {
public:
int f(const A& other) const { return 2; }
virtual int f(const B& other) const { return 3; }
};
void go(const A& a, const A& a1, const B& b) {
cout << a1.f(a) << endl; //Prints 2
cout << a1.f(a1) << endl; //Prints 2
cout << a1.f(b) << endl; //Prints 2
}
int main() {
go(A(), B(), B());
system("pause");
return 0;
}
I can understand why the first two will print 2. But I cannot understand why the last print is also 2. Why doesn't it prefers the overloaded function in B?
I already looked at this and this but I couldn't manage to understand from these.
int B::f(const B& other) const doesn't override int A::f(const A& other) const because the parameter type is not the same. Then it won't be called via calling f() on reference of the base class A.
If some member function vf is declared as virtual in a
class Base, and some class Derived, which is derived, directly or
indirectly, from Base, has a declaration for member function with the
same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or
not the keyword virtual is used in its declaration) and overrides
Base::vf (whether or not the word override is used in its
declaration).
If you use override specifier (since C++11) compiler will generate the error.
class B : public A {
public:
int f(const A& other) const { return 2; }
virtual int f(const B& other) const override { return 3; }
};
Such as Clang:
source_file.cpp:10:17: error: 'f' marked 'override' but does not override any member functions
virtual int f(const B& other) const override { return 3; }
^
If you add an overload for it in the base class, you might get what you want. Note that a forward declaration of class B will be needed.
class B;
class A {
public:
virtual int f(const A& other) const { return 1; }
virtual int f(const B& other) const { return 1; }
};
LIVE
It's easy, really. You're calling f on an object with static type A. A has only one f, so there's only one entry in the vtable for that function. Overload resolution takes place compile-time. The overload will only be resolved if you call it on an object whose static type is B
The confusion comes in that your:
int f(const A& other) const { return 2; }
line is actually virtual also and is overriding your line:
virtual int f(const A& other) const { return 1; }
Meanwhile, the line:
virtual int f(const B& other) const { return 3; }
ends up being completely ignored because everything matches to the "return 1" line, then follows polymorphically up the chain to the "return 2" line. As the other poster said, the const B portion means it won't match the polymorphic method call.
As an aside: If you're getting a 2 on the first line, I'm suspicious of undesired stack behavior. I'd expect a 1. Perhaps try allocating like this:
A a1;
B b1, b2;
go(a1, b1, b2);
I want to do the following:
class A{
private:
//some data
B b;
double f(double);
public:
A(){
b = new B(f); // does not work of course
}
};
class B{
public:
B(double (*func)(double));
};
Class B is supposed to solve a mathematical problem specified by the function func. Class A should now use B to solve this problem for func=f. The member function f accesses the private data members of A.
The problem is, of course that I cannot simply pass a pointer to member function. I know there are ways to do that, but B should still be able to take any function, not only members of A.
Until now, I just made f and the members of A static, but I think this is a rather bad design. Can you think of any workaround for this?
You can use the standard std::function<> template as a polymorphic wrapper for your functions.
Your class B simply store an instance of std::function<double (double)> and call it through foo :
class B
{
public:
B(const std::function<double (double)>& func) : func(func) {}
void foo(double d)
{
std::cout << func(d);
}
private:
std::function<double (double)> func;
};
While your class A build its B member with one of its member function (f), thanks to std::bind :
class A
{
public:
double md;
B b;
double f(double d) const
{
return md * d;
}
public:
A(double d) : md(d), b(std::bind(&A::f, this, std::placeholders::_1)) { }
};
We can now simply use it :
int main() {
A a(42);
a.b.foo(2); // Output : 84
}
Live demo here.
How about using polymorphism as an alternative to your current design?
For example:
class A
{
protected:
virtual double f(double x) = 0;
};
class B1 : public A
{
public:
double f(double x) {return x+1.0;}
};
class B2 : public A
{
public:
double f(double x) {return x+2.0;}
};
...
A* arr[4];
arr[0] = new B1;
arr[1] = new B2;
arr[2] = new B1;
arr[3] = new B2;
for (int i=0; i<4; i++)
cout << arr[i]->f(0.0);
This a fully working program for your sample.
#include <memory>
#include <iostream>
#include <functional>
class B
{
public:
B(std::function<double(double)> func)
{
std::cout<<func(1.0);
}
};
class A
{
private:
std::unique_ptr<B> b;
double f(double)
{
std::cout<<"A::f";
return 2.0;
}
public:
A() : b(new B(std::bind(&A::f, this, std::placeholders::_1)))
{
}
};
int main()
{
A a;
}
Please note you don't destroy b there and also keep in mind you are passing this to B, thing that might be dangerous (B might be alive after A is destroyed and if you use this inside f... boom!).
I would also suggest avoiding pointers and if this is not possible using std::unique_ptr
EDIT: And a version without b as pointer, std::function and std::bind
#include <iostream>
class A;
class B
{
public:
B(A* obj, double(A::*func)(double))
{
std::cout<<(obj->*func)(1.0);
}
};
class A
{
private:
B b;
double f(double)
{
std::cout<<"A::f";
return 2.0;
}
public:
A():b(this, &A::f)
{
}
};
int main()
{
A a;
}
Since function f() is not static it's type is "double ( A::* )(double)", not "double (*)(double)".
However for this particular case it is better re-design.
Does really A consist of data and instance of problem solver (class B), or A consist of data and delegates some operations to B?
Does really class B need some to know about methods from class A, or it expects data in some format?
class DataType {};
class ResultType {};
class A
{
DataType data;
DataType preprocess(Data d) {/*...*/}
ResultType process() { return B::compute(data); }
bool isSolvable() { return B::solve(preprocess(data)); }
};
class B
{
public:
ResultType compute(DataType);
bool solve(DataType);
};
Possible solution:
class A
{
B* b;
static double f(double d); //static change function type form `double(A::*)(double)` to `double(*)(double)`
public:
A()
{
b = new B(f);
}
}
only drawback that f cant take any data form A or B.
As is talked about in Item 33 in "More Effective C++", the assignment problem is
//Animal is a concrete class
Lizard:public Animal{};
Chicken:public Animal{};
Animal* pa=new Lizard('a');
Animal* pb=new Lizard('b');
*pa=*pb;//partial assignment
However, if I define Animal as an abstract base class, we can also compile and run the sentence:*pa=*pb. Partial assignment problem is still there.
See my example:
#include <iostream>
class Ab{ private: int a;
double b;
public:
virtual ~Ab()=0;
};
Ab::~Ab(){}
class C:public Ab{
private:
int a;
double b;
};
class D:public Ab{
private:
int a;
double b;
};
int main()
{
Ab *pc=new C();
Ab *pd=new D();
*pc=*pd;
return 0;
}
Do I miss something? Then what's the real meaning of the abstract base class?
I got the answer by myself. I missed a code snippet in the book.
Use protected operator= in the base class to avoid *pa=*pb. Use abstract base class to avoid animal1=animal2.Then the only allowed expressions are lizard1=lizard2;chicken1=chicken2;
See the code below:
#include <iostream>
class Ab{
private:
int a;
double b;
public:
virtual ~Ab()=0;
protected: //!!!!This is the point
Ab& operator=(const Ab&){...}
};
Ab::~Ab(){}
class C:public Ab{
public:
C& operator=(const C&){...}
private:
int a;
double b;
};
class D:public Ab{
public:
D& operator=(const D&){...}
private:
int a;
double b;
};
int main()
{
Ab *pc=new C();
Ab *pd=new D();
*pc=*pd;
return 0;
}
The abstract base class cannot help in case of assignment because the base sub-object is not instantiated (what an abstract class would block) but is sliced off the derived object (i.e. the assignment is done between already existing base sub-objects).
To avoid the problem the only solution I can think to is
make the assignment virtual
check in the assignment that the source instance is of the correct type
In code
#include <iostream>
struct Base {
int bx;
Base(int bx) : bx(bx) {}
virtual Base& operator=(const Base& other) {
bx = other.bx;
return *this;
}
};
struct A : Base {
int x;
A(int bx, int x) : Base(bx), x(x) {}
A& operator=(const Base& other) {
const A& other_a = dynamic_cast<const A&>(other);
Base::operator=(other);
x = other_a.x;
return *this;
}
};
struct B : Base {
int x;
B(int bx, int x) : Base(bx), x(x) {}
B& operator=(const Base& other) {
const B& other_b = dynamic_cast<const B&>(other);
Base::operator=(other);
x = other_b.x;
return *this;
}
};
The dynamic_cast<const A&>(other) is the operation that will fail if the object passed to the assignment operator is not of the correct derived type (it can be a sub-derived object, but this should be logically ok for an assignment source).
As an example:
int main(int argc, const char *argv[]) {
Base *pa1 = new A(1, 2);
Base *pa2 = new A(3, 4);
Base *pb1 = new B(5, 6);
Base *pb2 = new B(7, 8);
*pa1 = *pa2; std::cout << pa1->bx << "/" << dynamic_cast<A*>(pa1)->x << "\n";
*pb1 = *pb2; std::cout << pb1->bx << "/" << dynamic_cast<B*>(pb1)->x << "\n";
std::cout << "Ok so far\n";
*pa1 = *pb1; // Runtime error here (bad cast)
return 0;
}
It doesn't matter that your base class has pure virtual functions because you haven't defined the operator= for any of the classes. So when the compiler sees this statement:
*pc=*pd;
where pc and pd are both of type Ab, it will call the default assignment operator for Ab, which will result in partial assignment. As in the following example, I get the output as "Abstract Base" which is from abstract base class:
class A {
public:
virtual void foo() =0;
virtual A& operator=(const A& rhs) {
std::cout << "Abstract Base";
return *this;
}
};
class B : public A {
public:
virtual void foo() {
std::cout << "b:foo";
}
};
class C : public A {
public:
virtual void foo() {
std::cout << "c:foo";
}
};
int main()
{
A* b = new B();
A* c = new C();
*b = *c;
return 0;
}
Since you have not handled the assignment operators in your classes, you land up in situation partial assignment as Scot clearly describes in his article.
You need to handle assignments in your classes. In current design default implicit assignment operator of Ab is called and thus all the properties of children class are lost.
To avoid this you should have an implementation like this:
class Ab{ private: int a;
double b;
public:
virtual ~Ab()=0;
virtual Ab& operator=(const Ab& rhs){cout<<"in Ab="<<endl;}
};
Ab::~Ab(){}
class C:public Ab{
C& operator=(const Ab& rhs){cout<<"in C="<<endl;
return operator=(dynamic_cast<const C&>(rhs)); }
C& operator=(const C& rhs){
cout<<"do somethin in C="<<endl;
}
private:
int a;
double b;
};
class D:public Ab{
D& operator=(const Ab& rhs){cout<<"in D="<<endl;
return operator=(dynamic_cast<const D&>(rhs)); }
D& operator=(const D& rhs){
cout<<"do somethin in D="<<endl;
}
private:
int a;
double b;
};
I have a class with const members, and one constructor which calls another constructor with extra values filled in. Normally I could use a colon initializer for this, but the function is complex (printf/sprintf-like) and requires me to use a variable on the stack, so I have to do this in the body of the constructor and use assign *this to the new object. But of course this is invalid, because my member variables are const.
class A
{
public:
A(int b) : b(b), c(0), d(0) // required because const
{
int newC = 0;
int newD = 0;
myfunc(b, &newC, &newD);
*this = A(b, newC, newD); // invalid because members are const
// "cannot define the implicit default assignment operator for 'A', because non-static const member 'b' can't use default assignment operator"
// or, sometimes,
// "error: overload resolution selected implicitly-deleted copy assignment operator"
};
A(int b, int c, int d) : b(b), c(c), d(d) { };
const int b;
const int c;
const int d;
};
A a(0);
(I haven't explicitly deleted the assignment operator.) I declared the members const because I would like them to be public, but not mutable.
Is there some canonical way of solving this problem without using scary casts and force-overriding the members' constness? What's the best solution here?
You can add a parameters class and use either C++11 constructor delegation or a base class:
struct parameters {
int b; int c; int d;
parameters(int b): b(b), c(), d() {
myfunc(b, &c, &d);
}
};
// constructor delegation
class A {
public:
A(int b): A(parameters(b)) { }
A(parameters p): b(p.b), c(p.c), d(p.d) { }
};
// base/wrapper
class ABase {
ABase(parameters p): b(p.b), c(p.c), d(p.d) { }
};
class A: public ABase {
public:
A(int b): ABase(parameters(b)) { }
};
How about making a helper function:
class A
{
static int initializor(int b) { int n; myfunc(b, &n); return n; }
public:
explicit A(int b_) : b(b_), c(initializor(b_)) { }
A(int b_, int c_) : b(b_), c(c_) { }
// ... as before ...
};
I prefer Kerrek SB's answer, but in your case there is the complication that you can't easily make separate initialisation functions for each member.
In that case, another solution is to move the members to a base class and initialize that base class with a helper class with non-const members. Your initialization code is moved to the helper class' constructors, and can assign without problems.
class A_init
{
public:
A_init(int b)
{
// do whatever you like with c and d:
c = ...;
d = ...;
}
int c; // Note: non-const
int d; // Note: non-const
};
class A_base
{
public:
A_base(int b, A_init init) : b(b), c(init.c), d(init.d) {}
A_base(int b, int c, int d) : b(b), c(c), d(d) {}
const int b;
const int c;
const int d;
};
class A : public A_base
{
public:
A(int b) : A_base(b, A_init(b)) {}
A(int b, int c, int d) : A_base(b, c, d) {}
};
If one wants restrict access to A_init, one can switch to private and declare A a friend.
Where to put the results of myfunc so it can be set and used from different mem-initializers? How about in a default argument?
class A
{
private:
struct InitData;
public:
A(int b, InitData data=InitData());
A(int b, int c, int d) : b(b), c(c), d(d) { };
const int b;
const int c;
const int d;
};
struct A::InitData
{
int setup(int b);
int c;
int d;
};
inline int A::InitData::setup(int b)
{
myfunc(b, &c, &d);
return b;
}
inline A::A(int b_, InitData data)
: b(data.setup(b_)),
c(data.c),
d(data.d) {}
A a(0);
Since the made up type is private and has no conversions, there's little risk of accidentally using it or abusing it.
class A {
public:
void operator=(const B &in);
private:
int a;
};
class B {
private:
int c;
}
sorry. there happened an error. is assignment operator valid ? or is there any way to achieve this? [There is no relation between A and B class.]
void A::operator=(const B& in)
{
a = in.c;
}
Thanks a lot.
Yes you can do so.
#include <iostream>
using namespace std;
class B {
public:
B() : y(1) {}
int getY() const { return y; }
private:
int y;
};
class A {
public:
A() : x(0) {}
void operator=(const B &in) {
x = in.getY();
}
void display() { cout << x << endl; }
private:
int x;
};
int main() {
A a;
B b;
a = b;
a.display();
}
This isn't an answer, but one should be aware that the typical idiom for the assignment operator is to have it return a reference to the object type (rather than void) and to return (*this) at the end. This way, you can chain the assignent, as in a = b = c:
A& operator=(const A& other)
{
// manage any deep copy issues here
return *this;
}
Both assignment operator and parameterized constructors can have parameters of any type and use these parameters' values any way they want to initialize the object.
Others have clued in on this, but I'll actually state it. Yes you can use different types, but note that unless you use friend, your class cannot access the private members of the class it's being passed in with the operator.
Meaning A wouldn't be able to access B::c because it's private.