I'm coming from C# to C++ and when I try to construct tests, copy constructors are making it hard for me to mock the usual way I am accustomed to.
#include <iostream>
using namespace std;
class DB {
public:
virtual int getValue() { return 42; }
DB(const DB& source) { }
DB() { }
};
class DB_Mock: public DB {
public:
virtual int getValue() { return 999; }
};
class A {
public:
A(DB db) {
m_db = db;
}
void doIt() {
cout << "Result:" << m_db.getValue() << endl;
}
private:
DB m_db;
};
int main() {
/* prints 42 as expected */
DB db;
A a(db);
a.doIt();
/* prints 42, expected 999 */
DB_Mock db_mock;
A a2(db_mock);
a2.doIt();
return 0;
}
How do you approach problems like this?
m_db is not a reference or pointer, c++ polymorphism is work with only base class pointer or reference.
A(DB db) {
m_db = db; // m_db just sliced copy of base part of db.
}
Change this to reference like
class A
{
public:
explicit A(DB &db) : m_db(db) // it is initializing not copy
{
}
void doIt()
{
std::cout << "Result:" << m_db.getValue() << std::endl;
}
private:
DB &m_db; // Now m_db is reference
};
Compile and Run Here
Above will work But, You can not change reference value if you want to change use smart pointer[Recommended].
Reference :
Constructors and member initializer lists
Smart pointer
override
See virtual table to understand v_ptr
Edit:
As Pete Becker said be aware of lifetimes, if you pass local variable reference like
A make()
{
DB db;
A a(db);
return a;
}
int main()
{
const A &a = make();
// Wrong db is destroyed (dangling reference).
a.doIt(); // assume doIt(), getValue() are declared as const
return 0;
}
Above code is Wrong (undefined behaviour), So i Recommend to use smart pointer(Heap storage) to avoid this problems.
Thanks.
Related
I am currently learning c++ and I am an experienced C# and Java developer.
I have a class B which contains a member of class A, and I want users of class B to be able to change values in class A but not be able to change the instance of class A itself.
Basically it want to prevent b.getA() = anotherA; being allowed.
Is this possible in c++ or is my design completely wrong here?
This is my small c++ program
#include <string>
#include <iostream>
using namespace std;
class A {
public:
string getName()
{
return name;
}
void setName(string value)
{
name = value;
}
private:
string name = "default";
};
class B {
public:
A &getA()
{
return anInstance;
}
private:
A anInstance;
};
int main(int argc, char** argv) {
B b;
cout << b.getA().getName() << std::endl; // outputs "default"
b.getA().setName("not default");
cout << b.getA().getName() << std::endl; // outputs "not default"
A a;
a.setName("another a instance");
b.getA() = a; // I want to prevent this being possible
cout << b.getA().getName() << std::endl; // outputs "another a instance"
}
A C# example of what I am trying to do
class Program
{
class A
{
private string name = "default";
public string getName()
{
return name;
}
public void setName(string value)
{
name = value;
}
}
class B
{
private A anInstance;
public A getA()
{
return anInstance;
}
}
static void Main(string[] args)
{
B b = new B();
Console.WriteLine(b.getA().getName()); // outputs "default"
b.getA().setName("not default");
Console.WriteLine(b.getA().getName()); // outputs "not default"
}
}
You wrote:
A a;
a.setName("another a instance");
b.getA() = a; // I want to prevent this being possible
I ask, why?
Why do you want to prevent that?
Your next line is:
cout << b.getA().getName() << std::endl; // outputs "another a instance"
But that is misleading, you have not changed the instance of A inside b, you've only changed b.anInstance to be a copy of a. In other words, you've changed the name to say "another a instance" but that doesn't mean it's true. It's no more true that it's another instance than if you called b.getA().setName("another a instance") (in fact, the result is identical to doing that!)
Try it:
A a;
a.setName("another a instance");
std::cout << &b.getA() << std::endl;
b.getA() = a;
std::cout << &b.getA() << std::endl;
You'll get the same address printed both times, because b.getA() = a does not replace b.anInstance, it just modifies it, just like calling setName does.
That's because in C++ B::anInstance is not just a reference to an A, it is an A, and so by assigning to it you don't change the reference to point to a different A, you change the A itself.
So, to go back to your original question, since the thing you're worried about doesn't happen anyway why do you need to prevent it? If you already allow b.anInstance to be modified via the setName() function, why not just let it be modified by assignment as well?
If the answer to that question is that there are other properties of A which you don't want to be changed, and the assignment would change them, then instead of exposing the whole A object via B::getA() just add a new member function to B which sets the name. Doing this is better encapsulation than simply exposing the entire A object anyway. Too often Java and C# seem to encourage bad designs involving getters and setters for everything, which is pointless and encapsulates nothing; you might as well just make every member public and access them directly if there is a setter for everything.
If you want a B that contains an A that doesn't change except for its name, then don't expose the whole A, just provide a setter on the outer object:
class A {
public:
string getName() const // N.B. Added 'const' here
{
return name;
}
void setName(string value)
{
name = value;
}
private:
string name = "default";
};
class B {
public:
// Read-only access to the contained object:
const A& getA() const
{
return anInstance;
}
// Update the name of the contained object:
void setName(string value)
{
anInstance.name = value;
}
private:
A anInstance;
};
When you allow general non-const access to a member (such as A B::anInstance), then this implies access to all the (public) members of that member (const and not). In particular, you provide access to the operator=, which allows the contents of the member to be changed. Of course, it's still the same A (with the same address), but its data have changed.
In your C# code you are actually never allowing/using non-const access to the B::anInstance, so your C++ is not really equivalent. Consider
class B
{
A anInstance; // private by default
public:
A const& getA() const { return anInstance; } // const access only
A & getA() { return anInstance; } // full access
A copyA() const { return anInstance; } // make a copy
};
The first getA() is accessible from const B and only allows const access to anInstance, i.e. only to const members of A. The second getA() is only accessible from non-const B and allows full (public) access to anInstance, including A::operator=(A const&) (if present, i.e. either declared or not =delete in the definition of class A).
Finally, copyA() provides no access whatsover to B::anInstance, but returns merely a copy to it. Typically (if A is non-trivial and/or large) this requires much more effort than merely returning a reference (like a pointer), but in terms of usage/effect, it is very similar to getA() const (it's different if some const member of A actually change the state of A or if you use the dreaded const_cast<> as in const_cast<A&>(b.getA())=otherA).
You might want to use const pointer instead of reference, but it can have a lot of side effects:
class A {
public:
string getName() const
{
return name;
}
void setName(string value)
{
name = value;
}
private:
string name;
};
class B {
public:
A * const getA() const
{
return anInstance;
}
private:
A* anInstance;
};
int main(int argc, char** argv) {
B b;
cout << b.getA()->getName() << std::endl; // outputs "default"
b.getA()->setName("not default");
cout << b.getA()->getName() << std::endl; // outputs "not default"
A a;
a.setName("another a instance");
b.getA() = a; // I want to prevent this being possible
cout << b.getA()->getName() << std::endl; // outputs "another a instance"
}
As #Captain Price mentioned you can prohibit =operator of A class:
class A {
public:
string getName()
{
return name;
}
void setName(string value)
{
name = value;
}
private:
string name;
A& operator=(const A& other);
};
class B {
public:
A &getA()
{
return anInstance;
}
private:
A anInstance;
};
int main(int argc, char** argv) {
B b;
cout << b.getA().getName() << std::endl; // outputs "default"
b.getA().setName("not default");
cout << b.getA().getName() << std::endl; // outputs "not default"
A a;
a.setName("another a instance");
b.getA() = a; // I want to prevent this being possible
cout << b.getA().getName() << std::endl; // outputs "another a instance"
}
explicitly disable value-copying!
private:
A(const A&);
A& operator=(const A&);
I have a class that derives from a base class that contains its own member variable. In order to keep everything in the classes encapsulated, I'm trying to figure out a clean approach to setting this member variable at the same time retrieving it in the same method. Here is what the method looks like (this is pseudo code and probably won't compile):
class Base
{
virtual void MyVirtualMethod(double &output1, Object &output2)
{
// do base class stuff (does not set output1 because it does not need to)...
output2 = whatever;
}
}
class Derived
{
public:
virtual void MyVirtualMethod(double &output1, Object &output2)
{
// do derived class stuff...
m_DerivedMember = whatever;
// do more stuff...
output1 = m_DerivedMember;
output2 = whatever2;
}
private:
double m_DerivedMember;
}
Calling code #1
std::vector<DataPack> dataPack;
for each Base pointer...
{
double output1(100); // some default value
Object output2;
base->MyVirtualMethod(output1, output2);
dataPack.push_back(DataPack(output1, output2));
}
Calling code #2
double output1(100); // some default value
Object output2;
base->MyVirtualMethod(output1, output2);
// do more stuff but does not actually use output1, just output2...
While this works, it just doesn't seem clean to me. I guess the bigger question I'm asking myself is whether it's a good idea to use the same method as a getter and a setter at the same time? Thanks!
Although I don't recommend this, you can return a reference to your member, which will allow you both get/set operations. This is how std::vector works by overloading operator[]. Something like:
#include <iostream>
using namespace std;
class Foo
{
int m_;
public:
Foo(int m): m_(m){}
int& get_set()
{
return m_;
}
const int& get_set() const // for const-access
{
return m_;
}
};
int main()
{
Foo foo(10);
cout << foo.get_set() << endl;
foo.get_set() = 20;
cout << foo.get_set() << endl;
// that's why we need the `const` overload of `Foo::get_set`
const Foo cfoo(100);
cout << cfoo.get_set() << endl;
}
To answer your question, separate getters and setters are at the core of encapsulation. While it may save you an extra function call, it's much cleaner and safer to have separate functions for getting and setting. Here's some tweaked code to understand better
class Derived : public Base
{
public:
virtual void MyVirtualMethod(double &output1, Object &output2)
{
// do derived class stuff...
m_DerivedMember = whatever;
// do more stuff...
output1 = m_DerivedMember;
output2 = whatever2;
}
/*
The setter
*/
void setDerivedMember(double m){
m_DerivedMember = m;
}
/*
the getter
*/
double getDerivedMember(){
return m_DerivedMember;
}
private:
double m_DerivedMember;
}
And we could invoke these functions like:
Derived d(1.5, string("I'm a string"));
d.setDerivedMember(5.00);
cout <<"Derived Member Value: " d.getDerivedMember()<<endl;
It would output:
Derived Member Value: 5.00
Hope that makes sense!
I have two classes
class A { C* c; }
class B { D* d; }
and find I need to construct a std::vector whose elements are either A or B (with the sequence decided at run time. So I constructed a polymorphic
class Poly {
int oType;
void* oPtr;
}
as well as constructor
Poly::Poly(int type)
{
if (type == 1) oPtr = new (A*) oPtr();
if (type == 2) oPtr = new (B*) oPtr();
oType = type;
}
along with a similarly structured destructor. Now
std::vector<Poly*> test;
works. However, I am having trouble accessing the subobjects.
I tried
if (test->oType == 1) test->oPtr->a;
if (test->oType == 1) test->(A*)oPtr->a;
if (test->oType == 1) (A*)(test->oPtr)->a;
all giving me the compiler error:
'void*' is not a pointer-to-object type
How do I convince the compiler that it's OK to reference a, if I know that the type of oPtr is A*?
How do I convince the compiler that it's OK to reference a, if I know
that the type of oPtr is A*?
Strictly I think the answer to that is: ((A*)(test->oPtr))->a. The better way to do that in C++ uses the cast operator: static_cast<A*>(test->oPtr)->a
HOWEVER This is not typically how this problem is addressed in c++. So I have provided a more usual approach that you may find useful:
class Poly
{
public:
virtual ~Poly() {}
virtual void do_something() = 0; // each sub-type has its own version of this
};
class A: public Poly
{
public:
void do_something() /* override */ // c++11 only
{
std::cout << "Doing something A specific\n";
}
};
class B: public Poly
{
public:
void do_something() /* override */ // c++11 only
{
std::cout << "Doing something B specific\n";
}
};
int main()
{
std::vector<Poly*> polys;
// create data structure
polys.push_back(new A);
polys.push_back(new A);
polys.push_back(new B);
polys.push_back(new A);
// use objects polymorphically
for(size_t i = 0; i < polys.size(); ++i)
polys[i]->do_something();
// clean up memory (consider using 'smart pointers')
for(size_t i = 0; i < polys.size(); ++i)
delete polys[i];
}
As others mentioned, the polymorphic way is to use virtual functions.
Here is an implementation using smart pointers. The creator class is responsible for creating the Poly object we are asking for. This isolates the creation to one class.
Note that there are more sophisticated ways of doing this. The goal here is to show, more or less, how it would be done using C++.
#include <vector>
#include <memory>
#include <iostream>
class Poly
{
public:
virtual void Test() = 0;
};
typedef std::unique_ptr<Poly> PolyPtr;
class A : public Poly
{
public:
void Test() { std::cout << "Test for A" << "\n"; }
};
class B : public Poly
{
public:
void Test() { std::cout << "Test for B" << "\n"; }
};
class PolyCreator
{
public:
PolyPtr CreatePolyObject(int oType)
{
switch( oType )
{
case 1:
return PolyPtr(new A());
case 2:
return PolyPtr(new B());
}
throw "Could not find type in list";
}
};
int main()
{
PolyCreator pCreator;
std::vector<PolyPtr> PolyPtrVect;
// create objects
PolyPtrVect.push_back(pCreator.CreatePolyObject(1));
PolyPtrVect.push_back(pCreator.CreatePolyObject(2));
// call Test functions for each
std::vector<PolyPtr>::iterator it = PolyPtrVect.begin();
while ( it != PolyPtrVect.end())
{
(*it)->Test();
++it;
}
}
Output:
Test for A
Test for B
Note
There is only one if() statement that is isolated to the PolyCreator class.
There are no memory leaks due to usage of std::unique_ptr.
Poly is an abstract class. All derived classes must implement the Test function.
So I have 2 functions and 1 class.
with 1 function I want to Set value's of the integers stored in a class.
with the other function I want to use these value's again.
I'm using pointers as I thought this would be saved on Memory address's across the whole program.
#include <iostream>
using namespace std;
void Function1();
void Function2();
class TestClass
{
public:
TestClass();
~TestClass();
void SetValue(int localValue)
{
*value = localvalue;
}
int GetValue()const
{
return *value;
}
private:
*value;
};
TestClass::TestClass()
{
value = new int(0);
}
TestClass:
~TestClass()
{
delete value;
}
int main()
{
TestClass *tommy = new TestClass; //this didn't work,
//couldn't use SetValue or Getvalue in functions
Function1();
Function2();
return 0;
}
void Function1()
{
int randomvalue = 2;
TestClass *tommy = new TestClass; //because it didnt work in main, i've put it here
tommy->SetValue(randomvalue);
}
void Function2()
{
TestClass *tommy = new TestClass;
cout << tommy->GetValue();
<< endl; //this gave a error, so I put the above in again
//but this returns 0, so the value isn't changed
}
So, got a solution for me? I didn't got any compile errors, but the value isn't changed, probably because the destructor is called after Function1 has been completed. so how do I do it?
You need to pass your tommy from main() to each of your functions, not create a new one in each time, otherwise you're just losing the new Testclass objects you're creating in your functions, and actually here getting memory leaks because you use new.
Something like:
void Function1(TestClass * tommy) {
int randomvalue =2;
tommy->SetValue(randomvalue);
}
and then in main():
int main() {
TestClass *tommy = new TestClass;
Function1(tommy);
std::cout << tommy->GetValue() << std::endl; // Outputs 2
delete tommy;
return 0;
}
This is an odd use case, though - this would be the kind of thing you'd expect member functions to do. This would be better:
int main() {
TestClass *tommy = new TestClass;
tommy->SetValue(2);
std::cout << tommy->GetValue() << std::endl; // Outputs 2
delete tommy;
return 0;
}
without the need for Function1() and Function2(). Either way, you're going to have to fix:
private:
*value;
in your class, as someone else pointed out.
you are not passing your TestClass to either function so they functions can't see the tommy object you made. Then in each function you create a new local variable that just happens to have the same name as your local variable in main... They are all independent objects
Every time you write new TestClass, you are quite literally creating a new instance of a TestClass object. The new instance is not related to any existing instances in any way, except for being of the same type. To make the single instance of TestClass be "the one" being used by your functions, you need to pass it in as an argument to those functions.
Also -- Don't use pointers unless it is absolutely necessary.
Here's a cleaned up example of your code that accomplishes what it appears you were trying.
class TestClass
{
int value;
public:
TestClass() : value(0)
{}
int GetValue() const { return value; }
void SetValue(int x) { value = x; }
};
// takes a "reference", works somewhat like a pointer but with
// some additional safety guarantees (most likely will not be null)
// This will modify the original passed in TestClass instance.
void SetRandomValue(TestClass& tc)
{
int random = 2; // not really random...
tc.SetValue(random);
}
// take a const reference, similar to above comment, but a const
// reference cannot be modified in this scope
void Print(const TestClass& tc)
{
std::cout << tc.GetValue() << "\n";
}
int main()
{
// create a TestClass instance with automatic storage duration
// no need to use a pointer, or dynamic allocation
TestClass tc;
// Modify the instance (using reference)
SetRandomValue(tc);
// print the instance (using const reference)
Print(tc);
return 0;
}
I created some code to reproduce the problem:
#include "stdafx.h"
#include <iostream>
#include <vector>
class A
{
protected:
int m_X;
public:
A() {
std::cout << "in A ctor" << std::endl;
m_X = 0;
}
virtual void printX(){ std::cout << "in A " << m_X << std::endl; }
};
class B : public A
{
public:
B() {
std::cout << "in B ctor" << std::endl;
m_X = 1;
}
virtual void printX(){ std::cout << "in B " << m_X << std::endl; }
};
class As
{
public:
void AddA( const A &a ){ m_As.push_back( a ); }
void PrintXs()
{
for ( auto a : m_As )
{
a.printX();
}
}
private:
std::vector<A> m_As;
};
int _tmain(int argc, _TCHAR* argv[])
{
As as;
B b;
as.AddA( b );
as.PrintXs();
system("pause");
return 0;
}
The output of this is:
in A ctor
in B ctor
in A 1
I want "in B 1" instead of "in A 1". I'm sure my understanding of virtual is flawed. How must I change the code to call the B PrintX()? Note that there will be other classes that inherit from A so I really don't want to code a static call.
Thanks.
What you're doing is called slicing. This is where you take an object of a derived class and trim off everything that is not in the parent and assign it to the parent.
What you want to do is use polymorphism to do what you explained. To do this, change your vector from a copy of the object, to a ptr to the object.
If interested in more details, please use the links provided, the information included in them seems to be very complete.
The quick fix is to change your As class to the following:
class As
{
public:
void AddA( A &a ){ m_As.push_back( &a ); }
void PrintXs()
{
for ( auto a : m_As )
{
a->printX();
}
}
private:
std::vector<A*> m_As;
};
When you use std::vector<A> m_As;, the vector can only fit A objects. If you use pointers instead then polymorphism can work and call the correct printX function. However, this has the problem of dangling pointer if the lifetime of the pointed to object expires. To handle that it would be better to use a smart pointer class like std::unique_ptr.
Since you're passing objects by value you can not take advantages of polymorphism. Pass them by (smart) pointers or references.
std::vector<std::shared_ptr<A>> m_As;
// or
std::vector<std::unique_ptr<A>> m_As;
// or
std::vector<A*> m_As; // be careful of bare pointers
// or (since C++11)
std::vector<std::reference_wrapper<A>> m_As;
std::reference_wrapper magic!
For the last one, you can use std::reference_wrapper and std::ref:
class As
{
public:
void AddA(A &a){ m_As.push_back( std::ref(a) ); }
void PrintXs() const
{
for ( auto a : m_As )
{
a.get().printX();
}
}
private:
std::vector<std::reference_wrapper<A>> m_As;
};
Using last code, you don't have to change main code.
Live code
for ( const auto & a : m_As )
{
a.printX();
}
it will keep you from expanded copy and provide the B-instance instead of A-instance, appeared as copy.