undefined reference error for all methods of Base class - c++

I have following base class and derived class structure.
base/include/Base.h
namespace A
{
namespace B
{
class Base
{
public:
Base();
Base(const Type type, const Name name);
virtual ~Base();
// Copy constructor
Base(const Base& other);
// Assignment operator
Base& operator= (const Base& rhs);
// Comparison
bool operator< (const Base& rhs);
std::string toString();
//These enums have been defined in same file above the class
enum Type mType;
enum Name mName;
};
}
}
base/src/Base.cpp
#include "Base.h"
//and other required includes
namespace A
{
namespace B
{
Base::Base()
{
}
Base::Base(const Type type, const Name name)
{
}
Base::~Base()
{
}
// Copy constructor
Base::Base(const Base& other)
{
}
// Assignment operator
Base& Base::operator= (const Base& rhs)
{
}
// Comparison
bool Base::operator< (const Base& rhs)
{
}
std::string Base::toString()
{
}
}
}
base/test/test.h
#include "Base.h"
namespace A
{
namespace B
{
class Derived: public Base
{
public:
Derived();
Derived(const Type type, const Name name);
virtual ~Derived();
Derived(const Derived& other);
Derived& operator= (const Derived& rhs);
virtual std::string toString();
};
}
}
base/test/test.cpp
#include "test.h"
namespace A
{
namespace B
{
Derived::Derived()
{
}
Derived::Derived(const Type type, const Name name)
:Base(type, name)
{
}
Derived::~Derived()
{
}
Derived::Derived(const Derived& other)
{
}
Derived& Derived::operator= (const Derived& rhs)
{
}
std::string Derived::toString()
{
}
};
}
}
Now, I am building libBase.a for Base class directory.
And then I am trying to compile Derived class on command line like this in base/test directory:
g++ *.cpp -o Test \
-I /cygdrive/c/projects/base/include \
-L /cygdrive/c/projects/base/Build -lBase
But I get errors like:
/tmp/ccjLwXZp.o:Derived.cpp:(.text+0x10d): undefined reference to `A::B::Base::Base()
/tmp/ccjLwXZp.o:Derived.cpp:(.text+0x129): undefined reference to `A::B::Base::Base()
/tmp/ccjLwXZp.o:Derived.cpp:(.text+0x161): undefined reference to `A::B::base::Base(const Type type, const Name name)'
These errors I get for all the functions defined in base class.
I am not sure, what is it that I am doing wrong.
I have checked that libBase.a is in proper place

The problem might be related to the fact you've declared Type and Name enums after the c-tor declaration. Due to this the compiler can't build the Base class.
class Base
{
public:
enum Type mType; // <-- define the type and Name here, before
enum Name mName; // <-- the C-tor (actual usage)
Base();
Base(const Type type, const Name name);
virtual ~Base();
// Copy constructor
Base(const Base& other);
// Assignment operator
Base& operator= (const Base& rhs);
// Comparison
bool operator< (const Base& rhs);
std::string toString();
//These enums have been defined in same file above the class
//enum Type mType; // <<- your original location
//enum Name mName;
};

Related

How to make this operator= overload work?

I was experimenting with making the operator= be virtual, like so:
#include <iostream>
#include <string>
class Base {
public:
std::string field1;
Base(std::string str) : field1(str) {}
virtual Base& operator=(const Base& other)
{
field1 = other.field1;
return *this;
}
};
class Derived : public Base {
public:
std::string field2;
Derived(std::string str1, std::string str2) : Base(str1), field2(str2) {}
virtual Derived& operator=(const Derived& other) override
{
Base::operator=(other);
field2 = other.field2;
return *this;
}
};
However, this gives a compiler error, because the Derived function is not actually overloading anything, the signatures are different.
Is it possible to override the operator= to write code like this?
Base* ptr = new Derived("old 1", "old 2");
Derived derived("new 1", "new 2");
*ptr = derived; // <- use the derived class operator= to assign both field1 and field2
This operator
virtual Derived& operator=(const Derived& other);
does not override the copy assignment operator declared in the base class.
You have to write
Derived& operator=(const Base& other) override;
That is the type of the parameter shall be const Base &.
Here is a demonstrative program.
#include <iostream>
struct A
{
virtual A & operator =( const A & )
{
std::cout << "A::operator =\n";
return *this;
}
};
struct B : A
{
virtual B & operator =( const A &a ) override
{
A::operator =( a );
std::cout << "B::operator =\n";
return *this;
}
};
int main()
{
B b1;
A &rb1 = b1;
B b2;
b2 = rb1;
return 0;
}
Its output is
A::operator =
B::operator =

How to implicitly convert returned value to base class without invoking copy constructor?

Consider two classes such as these:
#include <cstdio>
using std::puts;
class Base {
public:
Base() { puts("Create base"); }
Base(const Base &) { puts("Copy base"); }
Base(Base &&) { puts("Move base"); }
virtual ~Base() { puts("Delete base"); }
Base & operator=(const Base &) = delete;
};
class Derived : public Base {
public:
Derived() { puts("Create derived"); }
Derived(const Derived &) { puts("Copy derived"); }
Derived(const Base &) { puts("Copy derived from base"); }
Derived(Derived &&) { puts("Move derived"); }
Derived(Base &&) { puts("Move derived from base"); }
virtual ~Derived() { puts("Delete derived"); }
Derived & operator=(const Derived &) = delete;
};
and a function:
Base fn() {
Derived d;
// Fill in d here
return d;
}
Copying the base class is a very expensive operation, however because the derived class is not much different, it could be converted into a base object using move semantics. However, I can't get the compiler to use that implicitly instead of the copy construction. I tried adding the following with no success:
Base::Base(Derived &&);
Derived::operator Base &&() &&;
Derived::operator Base() &&;
Is there a way to avoid the copy constructor by only changing the two classes and not the function fn?
EDIT: I know how to do it if I could change the function fn but I can't.
Base::Base(Derived &&); would work fine if added correctly.
#include <utility>
class Derived;
class Base {
// ...
Base(Derived &&);
};
// Derived here
Base::Base(Derived &&d) : Base(std::forward<Base>(d)) {}
The only tricky part is std::forward<Base>(d). But it's just a cast ultimately, where we are asking to forward d as a Base xvalue. Then the delegated move constructor does the right thing.
See it live
RVO is guaranteed to try and return the local variable as though it was an rvalue first. Since now there is a constructor matching it, it will work.

Virtual assignment operator not allowing static_cast

I have the following MWE code:
#include <algorithm>
class Base{
public:
int baseMember;
friend void swap(Base& in, Base& out)
{
using std::swap;
swap(in.baseMember, out.baseMember);
}
virtual Base& operator=(Base obj)
{
swap(*this, obj);
return *this;
}
Base() : baseMember(1)
{
}
};
class Derived : public Base
{
public:
int derivedMember;
friend void swap(Derived& in, Derived& out)
{
using std::swap;
swap(in.derivedMember, out.derivedMember);
swap(static_cast<Base&>(in), static_cast<Base&>(out));
}
virtual Base& operator=(Base obj)
{
swap(*this, static_cast<Derived&>(obj));
return *this;
}
Derived() : Base(), derivedMember(2)
{
}
};
int main()
{
Base *b1 = new Derived();
Base *b2 = new Derived();
*b1 = *b2;
delete b1;
delete b2;
}
I have two Base pointers pointing to Derived data. I then do an assignment of the contents of the pointers. Since the Base class' assignment operator is virtual, polymorphism kicks in and the assignment operator of the Derived class (with the same signature) is called instead.
However, the static_cast to transform the source into a Derived object fails. Or, well, it successfully transforms it into a Derived object, but its derivedMember is garbage (after being initially set in the constructor).
How can this be avoided? How can an assignment between the Derived contents of two Base pointers be done?
Your code has a typo and inherently unsafe behavior. The typo is here:
virtual Base& operator=(Base obj) // <-- should be base&
{
swap(*this, static_cast<Derived&>(obj));
return *this;
}
If you fix this, your code should work in the simple example provided. But it would still fail at large, because how would you guarantee the argument passed to operator= will be in fact of Derived type?
Passing an argument by value slices that argument. So by the time your operator= function is called, you have an actual Base, not a Derived.
I'm afraid you'll need to overload your assignment for lvalues and rvalues.
virtual Base& operator=(const Base&);
virtual Base& operator=(Base&&);

Swap-Idiom of abstract class with private data members

Assume we have this two classes, with implemented swap-idioms. The copy constructor and assignment operator of the base class are deleted, as it makes no sense. However the swap-method is implemented, as it holds a member.
namespace std
{
template<>
void swap<Base>(Base& a, Base& b)
{
a.swap(b);
}
template<>
void swap<Derived>(Derived& a, Derived& b)
{
a.swap(b);
}
}
class Base
{
public:
Base(int ID) : ID_(ID) {}
virtual std::string getString()=0;
Base(const Base&)=delete;
operator=(const Base&)=delete;
void swap(Base& rhs)
{
std:swap(ID_, rhs.ID_);
}
private:
int ID_;
}
class Derived : public Base
{
public:
Derived(int ID, bool Value) : Base(ID), Value_(Value) {}
virtual ~Derived() {}
Derived(Derived& rhs)
{
std::swap(*this, rhs);
}
virtual std::string getString() {return Value_ ? "True" : "False"}
void swap(Derived& lhs, Derived& rhs)
{
std::swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs);
std::swap(lhs.Value_, rhs.Value_);
}
private:
bool Value_;
}
As seen in many examples, this would be the standard way to do it I suppose.
However, I see a problem with the public Base::swap, as it should not be possible to swap only the abstract base-class!
Wouldn't it be better to remove the template for the Base class and make the Base::swap Method protected:
class Base
{
...
protected:
void swap(Base& rhs, Base &lhs);
}
class Derived : public Base
{
...
public:
void swap(Derived& lhs, Derived& rhs)
{
Base::swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs);
std::swap(lhs.Value_, rhs.Value_);
}
}
Assuming, there is another class derived from base, with the first implementation it would be possible to swap the ID, however the data members of the derived objects would stay the same.
So, am I right thinking that swapping of a abstract class should not be possible from outside?
The copy constructor and assignment operator of the base class are deleted, as it makes no sense.
Actually, this is terrible. Now you made Derived uncopyable! Why? There is no reason to add this restriction. The default copy constructor and assignment operator of Base are perfectly reasonable in the context of copying the most-base class of the hierarchy.
Once you undo that, there's no need to do anything else as std::swap(derived1, derived2) would already do the right thing. The default move construction/operation is correct. It's always good to let the compiler do things for you.
But if you want to override swap anyway, the correct way to do that would be as a non-member friend:
class Base {
...
friend void swap(Base& lhs, Base& rhs) {
using std::swap;
swap(lhs.ID_, rhs.ID_);
}
};
class Derived : public Base {
...
friend void swap(Derived& lhs, Derived& rhs) {
using std::swap;
swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs));
swap(lhs.Value_, rhs.Value_);
}
};
Also, your Derived copy constructor makes no sense. Remove it as per the first paragraph of my answer.

calling operators of base class... safe?

Is following pattern ok/safe ? Or are there any shortcomings ?
(I also use it for equality operators)
Derived& operator=(const Derived& rhs)
{
static_cast<Base&>(*this) = rhs;
// ... copy member variables of Derived
return *this;
}
This is fine, but it's a lot more readable IMHO to call the base-class by name:
Base::operator = (rhs);
Yes, it's safe.
A different syntax to do the same thing could be:
Base::operator=( rhs );
That's better to use
Base::operator=(rhs);
because if your base class have a pure virtual method the static_cast is not allowed.
class Base {
// Attribute
public:
virtual void f() = 0;
protected:
Base& operator(const Base&);
}
class Derived {
public:
virtual void f() {};
Derived& operator=(const Derived& src) {
Base::operator=(src); // work
static_cast<Base&>(*this) = src; // didn't work
}
}