Having this code:
#include <iostream>
#include <vector>
#include <string>
class A{
public:
A(std::string const& name) : name(name) {}
std::string const& getName() const {
return name;
}
private:
std::string name;
};
class B{
public:
void add(A const& a){
//vec.emplace_back(a) does not help either
vec.push_back(a);
}
std::vector<A> const& getVec() const {
return vec;
}
private:
std::vector<A> vec;
};
class C{
public:
C(B const& b, A const& a) : a(a), b(b) {}
A const& getA() const {
return a;
}
B& getB() {
return b;
}
private:
A a;
B b;
};
class D{
public:
C& add(C& c){
A const& a = c.getA();
B& b = c.getB();
b.add(a);
vec.push_back(c);
return c;
}
private:
std::vector<C> vec;
};
int main(){
A a1{"first"};
A a2{"second"};
B b;
C c1{b, a1};
C c2{b, a2};
D d;
d.add(c1);
d.add(c2);
for(A const& a : b.getVec()){
std::cout << a.getName() << ' ';
}
}
There is no output from the program, but
I would expect output:
first second
Where the B class is holding the vector, and D is trying to modify it (c.getB().add()) via class C. It's just simple example (encountered in a school project), but I wanted to know by this example the flow of changes between classes.
C's members are not reference types. Both c1 and c2 are storing copies of the constructor arguments.
So
d.add(c1);
d.add(c2);
doesn't affect b in main, only the members of c1 and c2, which are copies of the original b, a1 and a2 in main.
Related
You can redefine operator << in class by overload it.
However, how do you code it so that it would operates specific to a certain class member?
for example
class C
{
int a;
double b;
}
// I would like something like
void main ()
{
C c;
c.a << 1; // sets class member a to value 1;
}
I want a operator defined in Class C that operates specifically to class member a.
a pesudo-code would be
class C
{
int a;
double b;
void operator << (istream & fin)
{
... fin.get()... some code
}
}
Stating the obvious for a moment, assuming the variable is public, you'd use:
class C
{
int a;
double b;
}
// I would like something like
void main ()
{
C c;
c.a = 1; // sets class member a to value 1;
}
The << and >> operators are bit shifts, which have their own meaning. Overloading those for your own purpose is probably a bad idea.
The C++ way of doing things is to avoid setting member variables externally where possible (e.g. using RAII approaches, to set data at initialisation)....
class C
{
public:
C(int a, double b) : a(a), b(b) {}
int getA() const { return a; }
double getB() const { return b; }
private:
int a;
double b;
};
.... Or by adding a setter method if you really need it, e.g.
class C
{
public:
C(int a, double b) : a(a), b(b) {}
int getA() const { return a; }
double getB() const { return b; }
void setA(int v) { a = v; }
void setB(double v) { b = v; }
private:
int a;
double b;
};
You could in theory generate a new type, and overload the operators for that type, but it's not something I'd recommend (because changing the meaning of an operator is almost always a bad idea)
struct MyIntType {
int i;
// overload cast operator
operator int () {
return i;
}
// assign
MyIntType& operator = (const int& v) {
i = v;
return *this;
}
// not recommended :(
MyIntType& operator << (const int& v) {
i = v;
return *this;
}
};
class C
{
public:
MyIntType a;
double b;
};
void main ()
{
C c;
c.a << 1;
}
Having read your comment above, it sounds like you want to do this:
class C
{
public:
// I'm still not recommending this :(
C& operator << (const int& v) {
a = v;
return *this;
}
private:
int a;
double b;
};
void main ()
{
C c;
c << 1; //< now sets c.a
}
I have the following problem which I guess I am solving incorrectly given the problem I am facing:
I have an interface I and implementations A, B, C... I want to somehow express that I can get some results from couples (f(A, A), f(B, B), f(C, C)) and so on. In other words, I want to interface I to express that 2 identical implementations can be combined to produce some results, while others can be not (you can't get any valid result from f(A, B)).
Right now I have the following:
#include <iostream>
using namespace std;
class A;
class B;
class I{
public:
virtual int f (const I &other) const = 0;
virtual int fSpecific (const A &other) const { throw runtime_error(""); };
virtual int fSpecific (const B &other) const { throw runtime_error(""); };
};
class A: public I{
public:
A(int a) : a(a) {}
int f (const I &other) const override { other.fSpecific(*this); }
int fSpecific (const A &other) const override { /*logic here*/ return a + other.a; }
int a;
};
class B: public I{
public:
B(int b1, int b2) : b1(b1), b2(b2) {}
int f (const I &other) const override { other.fSpecific(*this); }
int fSpecific (const B &other) const override { /*logic here*/ return b1*b1 + b2*b2 + other.b1*other.b1 + other.b2*other.b2; }
private:
int b1;
int b2;
};
int f(const I &a, const I &b) {
a.f(b);
}
int main()
{
cout << f(A(1), A(2)) << std::endl; // prints 3
cout << f(B(1, 2), B(3, 4)) << std::endl; // prints 30
cout << f(A(1), B(3, 4)) << std::endl; // throws an error
return 0;
}
/*and so on*/
But I guess I use a wrong architecture. as adding classes results in changing I. Are there any better solution to express this such a relation?
Your interface is indeed strange, asking for method which should not be implemented.
We don't have multiple dynamic dispatch, except with std::visit of std::variant.
So following might help:
using V = std::variant<A, B, C>;
int f(const V& v1, const V& v2) {
struct {
template <typename T1, typename T2>
int operator()(const T& t1, const T2& t2) const { throw runtime_error(""); };
int operator()(const A& a1, const A& a2) const { return a1.a + a2.a; };
int operator()(const B& b1, const B& b2) const { return b1.b1*b1.b1 + b1.b2*b1.b2 + b2.b1*b2.b1 + b2.b2*b2.b2; };
int operator()(const C& c1, const C& c2) const { return c1.c * c2.c; };
} visitor;
return std::visit(visitor, v1, v2);
}
or keeping you hierarchy:
using CV = std::variant<const A*, const B*, const C*>;
class I
{
public:
virtual ~I() = default;
virtual CV asVariant() const = 0;
};
class A: public I{
public:
A(int a) : a(a) {}
CV asVariant() const override { return this; }
friend int f (const A& a1, const A& a2) { /*logic here*/ return a1.a + a2.a; }
int a;
};
class B: public I{
public:
B(int b1, int b2) : b1(b1), b2(b2) {}
CV asVariant() const override { return this; }
friend int f (const B& b1, const B& b2) {
/*logic here*/ return b1.b1*b1.b1 + b1.b2*b1.b2 + b2.b1*b2.b1 + b2.b2*b2.b2;
}
private:
int b1;
int b2;
};
int f(const I& i1, const I& &2) {
struct {
template <typename T1, typename T2>
int operator()(const T1*, const T2*) const { throw runtime_error(""); };
template <typename T>
int operator()(const T* t1, const T* t2) const { return f(*t1, *t2); };
} visitor;
return std::visit(visitor, i1.AsVariant(), i2.AsVariant());
}
You may employ dynamic_cast:
class I {
public:
template<typename T>
void fSpecific (T &other) {
if (dynamic_cast<T*>(this))
std::cout << "OK" << std::endl;
else
std::cout << "ERROR" << std::endl;
}
virtual ~I() {}
};
class A : public I {
};
class B : public I {
};
int main()
{
A a;
a.fSpecific(a);
B b;
b.fSpecific(a);
b.fSpecific((I&)a);
return 0;
}
There are some problems however:
Multiple inheritance
Objects need to be dynamically castable (that is why I added a virtual interface)
Casting to I also works.
Here is the test code:
class A{};
class B : public A{};
void Test(const std::vector<A>& a)
{
}
int main()
{
std::vector<A> a;
std::vector<B> b;
Test(a);
Test(b);//Compiler Error
return 0;
}
Since std::vector<A> and std::vector<B> is different type, we can't make conversion from one to another.
An optional way can be:
class A{};
class B : public A{};
void Test(const std::vector<A>& a)
{
}
int main()
{
std::vector<A> a;
std::vector<B> b;
Test(a);
Test(std::vector<A>(b.begin(), b.end()));
return 0;
}
It acts, but it takes extra copying from B to A. If A or B is a large object, it can be very slow. A better choice is:
class A{};
class B : public A{};
void Test(const std::vector<A>& a)
{
}
int main()
{
std::vector<A> a;
std::vector<B> b;
Test(a);
Test(std::vector<A>(std::make_move_iterator(b.begin()), std::make_move_iterator(b.end())));
return 0;
}
Since it just move the iter instead of the whole B class, it take a better performance. But there are some extra cost - If b is a very large vector with huge number of items, iteration also can slow down my code.
So I wonder if there is a way to directly convert std::vector<B> to std::vector<A> without any extra cost?
One approach is to make the vector a template parameter of the Test function. The calling code will remain the same, there is no copying required.
#include <vector>
#include <iostream>
class A{
public:
virtual void print() const {
std::cout << "A" << std::endl;
}
};
class B : public A{
virtual void print() const {
std::cout << "B" << std::endl;
}
};
template <typename ContainerA>
void Test(const ContainerA& aas)
{
for(const A& a:aas) {
a.print();
}
}
int main()
{
std::vector<A> a;
a.push_back(A());
std::vector<B> b;
b.push_back(B());
Test(a);
Test(b);
return 0;
}
I don't know if it's useful for you but the best I can think is pass std::vector<Derived> to the function and iterate the element as Base elements.
Something like
template <typename D>
void Test (std::vector<D> const & v)
{
for ( A const & elem : v )
{
// use elem
}
}
Using SFINAE you can enable Test() only for vectors of Base or derived from Base elements as follows
template <typename D>
typename std::enable_if<std::is_base_of<A, D>::value>::type
Test (std::vector<D> const & v)
{
for ( A const & elem : v )
{
// use elem
}
}
So you have
int main ()
{
std::vector<A> a;
std::vector<B> b;
std::vector<int> c;
Test(a); // compile
Test(b); // compile
// Test(c); // compiler error
}
Let's say we have the following scenario:
We have a base abstract class A. Then we have classes B and C which derived from A. We also have class D which is a custom implementation of a std::vector<T> - it contains a private property list of type std::vector<T> and some custom methods to work with it.
Now my problem is as follows: I would like to overload the operator + in class A to be able to do this:
B* b = new B();
C* c = new C();
D mList = b+c; //the property *list* of mList would contain b an c
I have tried everything and can't seem to be able to get it to work and am out of ideas. Is it even possible to override an operator in a base abstract class so that it will apply to derived classes?
EDIT:
Here is what I have tried so far:
File A.h:
#pragma once
#include <string>
#include <iostream>
using namespace std;
class A
{
protected:
double price;
string name;
public:
A() :name(""){};
A(string n, double p){
price = p;
name = n;
};
~A(){};
virtual void calculate(double value) = 0;
virtual void print() const = 0;
};
File B.h:
#pragma once
#include "A.h"
class B : public A
{
private:
public:
B() :A(){};
B(string n, double p) :A(n,p){};
~B();
void calculate(double value)
{
price = price + value;
}
void print() const
{
cout << name << " says: " << " " << price;
}
};
File C.h:
#include "A.h"
class C : public A
{
private:
public:
C() :A(){};
C(string n, double p) : A(n,p){};
~C();
void calculate(double value)
{
price = price * value;
}
void print() const
{
cout << name << " says: " << " " << price;
}
};
File D.H:
#include <vector>
class D
{
private:
vector<A*> list;
public:
D(){}
~D()
{
int len = list.size();
for (int i = 0; i < len; i++)
{
delete list[i];
}
};
void push(A* item)
{
list.push_back(item);
}
A* pop()
{
A* last = list.back();
list.pop_back();
return last;
}
//I have tried overriding it here and in A.h
friend D D::operator+(A* first, A* second)
{
D temp;
temp.push(first);
temp.push(second);
return temp;
}
};
It looks like you're are adding two pointers, so A::operator+() won't even be called. But to answer your question, yes, operator overloading is inheritable. Even from an abstract base class.
class A
{
public:
virtual void test() = 0;
int operator+(const A &a) {return 42;}
};
class B : public A
{
void test() {};
};
class C : public A
{
void test() {};
};
int main()
{
B* b = new B();
C* c = new C();
cout << "result: " << *b + *c << endl;
return 0;
}
Output:
result: 42
When c in C* and d is a D* if you write c+d you're just adding pointers, whatever overloads you defined.
Maybe you could redefine pointer addition for A* with a global operator(A*, A*) (not sure it's possible) but it would be quite dangerous for users since it overrides standard behavior.
The better solution is to define operators on references (const) and not pointers, which in your case is a little less convenient since you'd have to write: list = *c + *d;
Also, since you're using containers of pointers for polymorphism, I strongly recommend using shared_ptr.
Working code below (simplified, but with the ability to add more than 2 elements):
#include <list>
using std::list;
struct A {
list<const A*> operator+(const A& right) { // A + A
list<const A*> r;
r.push_back(this);
r.push_back(&right);
return r;
}
list<const A*> operator+(const list<const A*> & right) { // A + list
list<const A*> r = right;
r.push_front(this);
return r;
}
virtual void print() const = 0;
};
list<const A*> operator+(const list<const A*> & left, const A & right) { // list + A
list<const A*> r = left;
r.push_back(&right);
return r;
}
#include <iostream>
struct B : A {
void print() const { std::cout << "B" << std::endl; }
};
struct C : A {
void print() const { std::cout << "C" << std::endl; }
};
int main() {
B b;
C c;
B* pb = new B;
list<const A*> lst = b + c + *pb;
for(list<const A*>::iterator i = lst.begin(); i != lst.end(); ++i) {
(*i)->print();
}
return 0;
}
Take a look at this code-example:
#include <iostream>
class B;
class A;
class A
{
public:
virtual void overrideProp() = 0;
friend int operator+(const B& b, const A& a);
friend std::ostream& operator<<(std::ostream& os, const A& a)
{
return os << a.prop;
}
protected:
int prop;
};
class B : public A
{
public:
B(){overrideProp();}
void overrideProp(){prop=1;}
};
class C : public A
{
public:
C(){overrideProp();}
void overrideProp(){prop=3;}
};
int operator+(const B& b, const A& a)
{
return b.prop + a.prop;
}
class D
{
public:
void operator=(const int& i){d = i;}
friend std::ostream& operator<<(std::ostream& os, const D& a)
{
return os << a.d;
}
private:
int d;
};
int main()
{
B b;
C c;
D d; d = b+c;
std::cout << "B contains: " << b << " C contains: " << c << " D contains: " << d;
}
The output is B contains: 1 C contains: 3 D contains: 4
Here's an compilable and runnable example (http://codepad.org/cQU2VHMp) I wrote before you clarified the question, maybe it helps. The idea is that the addition overload can either be unary (and D defined as a friend), as here, or defined as a non-member binary operator using public methods. Note that I have to dereference the pointers b and c to make this work, as adding pointers often don't make sense.
#include <iostream>
#include <string>
class D {
public:
void Foo() {
std::cout << "D: " << member_ << std::endl;
}
friend class A;
private:
std::string member_;
};
class A {
public:
virtual void Foo() = 0;
A(const std::string &member) : member_(member) {}
D operator+(const A &rhs) {
D out;
out.member_ = member_ + " " + rhs.member_;
return out; // Uses the default copy constructor of D
}
protected:
std::string member_;
};
class B : public A {
public:
B(const std::string &member) : A(member) {}
void Foo() {
std::cout << "B: " << member_ << std::endl;
}
};
class C : public A {
public:
C(const std::string &member) : A(member) {}
void Foo() {
std::cout << "C: " << member_ << std::endl;
}
};
int main() {
B *b = new B("hello");
C *c = new C("world");
b->Foo();
c->Foo();
D d = (*b) + (*c);
d.Foo();
delete b;
delete c;
return 0;
}
The output of this program is:
B: hello
C: world
D: hello world
I get a runtime error with the following code, which is a reproducible reduction of my actual code. I am sure I am not instantiating something properly, but I cannot figure out what it is.
#include <iostream>
using namespace std;
class A {
int n;
public:
A();
A(const int k);
int getn() const { return n; };
};
A::A() : n(0) {};
A::A(const int k) : n(k) {}
class B {
const A& myA;
public:
B(const A& anA);
int getn() const { return myA.getn(); };
};
B::B(const A& anA) : myA(anA) {}
class C {
const A& myA;
const B& myB;
public:
C(const A& anA);
int getn() const { return myB.getn(); };
};
C::C(const A& anA) : myA(anA), myB(myA) {}
class D {
A myA;
C myC;
public:
D(const int k);
int getAn() const { return myA.getn(); };
int getCn() const { return myC.getn(); };
};
D::D(const int k) : myA(k), myC(myA) {}
int main() {
D myD(10);
cerr << "A: " << myD.getAn() << '\n';
cerr << "C: " << myD.getCn() << '\n';
}
I either get a segmentation fault on the second line of output or "C:0", instead of "C:10" which I expect.
The problem is in this line:
C::C(const A& anA) : myA(anA), myB(myA) {}
myB is a reference. But to what? The answer is to a temporary. myB(myA) will construct a temp object that is assigned to your reference. Unfortunately this object will be destroyed after the Ctor exits.
Change your code to the following:
class C {
const A& myA;
const B myB;
public:...
and it should work.
BTW: I nearly always declare constructors with one argument as explicit. Do so and the compiler will warn you.
You are trying to initialize D::myC with reference to D::myA, this is not correct because object is not completely constructed at this moment.
D::D(const int k) : myA(k), myC(myA) {}