So I have an abstract base class, Collection. I understand that it is abstract because it declares at least one pure virtual function.
I have a subclass of Collection, OrderedCollection, which declares those functions exactly in it's own header file. I then define those exact same functions in OrderedCollection's Source file.
Here is the code:
Class Collection.h
class Collection {
public:
virtual Collection& add(int i, int index) = 0; //pure virtual
virtual Collection& remove(int i) = 0; //pure virtual
virtual Collection& operator=(const Collection& other)=0; //pure virtual
virtual int& operator[](int i) = 0; //pure virtual
Collection& iterate(void (*pFunc)()); //Function takes pointer to function as argument
bool contains(int i);
virtual Collection& copy();
virtual ~Collection();
int size() { return size; }
int capacity() { return capacity; }
//virtual void swap(Collection& other);
protected:
Collection(){}
std::vector collectionVec;
int size;
int capacity;
};
Derived class OrderedCollection.h:
class OrderedCollection : public Collection
{
public:
OrderedCollection& add(int i, int index);
OrderedCollection& remove(int i);
OrderedCollection& operator=(const OrderedCollection& other);
int& operator[](int i);
OrderedCollection();
//OrderedCollection::OrderedCollection(int pFirst, int pLast, int pSize, int pCapacity, std::vector<int> passedVec);
//OrderedCollection(const OrderedCollection& other); //Copy constructor
virtual ~OrderedCollection();
virtual OrderedCollection& copy(OrderedCollection& passedCollection);
protected:
//int* first;
//int* last;
int first;
int last;
OrderedCollection& grow(); //Utility Function
};
aaand OrderedCollection.cpp:
#include "OrderedCollection.h"
OrderedCollection& OrderedCollection::add(int i, int index){
if(size == capacity){ //If vector is full
}
return *this;
}
OrderedCollection& OrderedCollection::remove(int i){
if(first <= last){
for(int j = first; j <= last; j++){
if(collectionVec.at(j) == i){
collectionVec.erase(j);
last--;
}
}
}
/*for(int j = 0; j < collectionVec.size(); j++){
if(collectionVec.at(j) == i)
} */
return *this;
}
OrderedCollection& OrderedCollection::operator=(const OrderedCollection& other){
if (this != &other) // protect against invalid self-assignment
{
// 1: allocate new memory and copy the elements
std::vector<int> *new_vector = new std::vector<int>(other.capacity);
std::copy(other.collectionVec, other.collectionVec + other.capacity, new_vector);
// 2: deallocate old memory
collectionVec.clear();
// 3: assign the new memory to the object
collectionVec = *new_vector;
size = other.size; //wtf
capacity = other.capacity; //wtf
delete new_vector;
}
// by convention, always return *this
return *this;
}
int& OrderedCollection::operator[](int i){ //is return type correct? It makes more sense to have a return type of int or int&, right?
int temp = 0;
if(first <= last){
if(collectionVec.at(first + i) != NULL){ //Need to redo this
return collectionVec.at(first + i);
}
}
return temp;
}
OrderedCollection::OrderedCollection() : Collection()
{
//first = &collectionVec.at(2);
//last = &collectionVec.at(1);
//Crossed at construction
first = 2;
last = 1;
}
OrderedCollection::~OrderedCollection(void)
{
//first = NULL;
//last = NULL;
collectionVec.clear();
}
OrderedCollection& OrderedCollection::grow(){
int newFirst = capacity / 2;
std::vector<int> *new_vector = new std::vector<int>(2 * capacity);
std::copy(collectionVec, collectionVec+size, new_vector->begin() + newFirst); //Want to return iterator pointing to
collectionVec = new_vector;
first = newFirst;
last = first + size;
capacity = collectionVec.size;
delete new_vector;
return *this;
}
OrderedCollection& OrderedCollection::copy(OrderedCollection& passedCollection){
OrderedCollection* temp = new OrderedCollection() //ERROR is here. VS highlights constructor method
return *this;
}
Now the issue comes when I am trying to create either a value identifier of type OrderedCollection within this last copy() here. As I understand it, I shouldn't be allowed to do this if the class is abstract (so clearly it is abstract, also VS tells me so). But there is another issue; I get the same error when I try to create a new OrderedCollection object and assigning it to temp. The above intialization is fine according VS (no complaints from the IDE, although it doesnt help me any). But I can't figure out why it's regarding this class as abstract.
Correct me if I'm wrong, but this should cover all of the bases in making sure that this derived class is NOT abstract..
There are no pure virtual functions declared within the derived class
All functions that were pure virtual in the base class, have been overridden in the derived class.
All of the overridden functions match the relevant function argument signature & return type, as originally declared in the base class.
The error exactly is, Error: object of abstract class type "OrderedCollection" is not allowed... And this is when I try to assign a pointer object to a new instance of OrderedCollection within this copy() method at the bottom.
Let me post my Collection.cpp file below:
#include "Collection.h"
Collection::Collection()
{
size = 0;
capacity = 4;
collectionVec.resize(capacity);
}
Collection::~Collection()
{
}
Collection& Collection::iterate(void (*pFunc)()){
return *this;
}
bool contains(int i){
return true;
}
Edit: Added Collection.cpp file and updated some fixes I've made in regards to mismatching function parameters.
virtual Collection& operator=(const Collection& other)=0;
is not being overridden in the child class, because:
OrderedCollection& operator=(OrderedCollection& other);
Has a different signature.
The difference is not just the 'const', but the actual type. The overridden class must also take a Collection, and not the derived OrderedCollection.
Related
So I tried to make a custom string & vector class (from a youtube channel named The Cherno). But when I tried to make a copy constructor on that vector class with my custom string class, I get this exception: str was nullptr (Occured in the string copy constructor) and also when I tried with a primitive data types (int) I also get this exception: std::move<int & __ptr64>(...) returned nullptr (Occured on the re_allocate function).
main.cpp:
int main() {
utils::list<int> list;
list.place(5);
utils::list<int> other = list; // Works fine if I remove this line
}
String copy constructor:
utils::string::string(const string& other)
: pr_Length(other.pr_Length)
{
// If the other string was not initialized then return
if (!other.pr_Init) {
pr_Init = false;
return;
}
// Allocates a new char*
pr_Data = new char[pr_Length + 1];
// Copy all the char* on other string and copy it here
std::memcpy(pr_Data, other.pr_Data, pr_Length + 1);
// This string is initialized
pr_Init = true;
}
Vector class:
template<typename T>
class list {
private:
T* pr_Array;
size_t pr_Size;
size_t pr_Cap;
public:
using ValType = T;
using Iterator = list_iterator<list<T>>;
list() {
re_allocate(2);
}
~list() {
destroy_all();
::operator delete(pr_Array, pr_Cap * sizeof(T));
}
list(const list& other)
: pr_Size(other.pr_Size), pr_Cap(other.pr_Cap)
{
re_allocate(pr_Cap);
}
void add(const T& elem) {
if (pr_Size >= pr_Cap) {
re_allocate(pr_Cap + 2);
}
new(&pr_Array[pr_Size]) T(std::move(elem));
pr_Size++;
}
void add(T&& elem) {
if (pr_Size >= pr_Cap) {
re_allocate(pr_Cap + 2);
}
new(&pr_Array[pr_Size]) T(std::move(elem));
pr_Size++;
}
template<typename...Args>
T& place(Args&&... args) {
if (pr_Size >= pr_Cap) {
re_allocate(pr_Cap + 2);
}
new(&pr_Array[pr_Size]) T(std::forward<Args>(args)...);
return pr_Array[pr_Size++];
}
void destroy_back() {
if (pr_Size == 0) {
return;
}
pr_Array[pr_Size].~T();
pr_Size--;
}
void destroy_all() {
for (size_t i = 0; i < pr_Size; i++) {
pr_Array[i].~T();
}
pr_Size = 0;
}
const T& operator[](size_t i) const {
return pr_Array[i];
}
T& operator[](size_t i) {
return pr_Array[i];
}
const size_t size() const {
return pr_Size;
}
size_t size() {
return pr_Size;
}
Iterator begin() {
return Iterator(pr_Array);
}
Iterator end() {
return Iterator(pr_Array + pr_Size);
}
private:
void re_allocate(size_t cap) {
T* newBlock = (T*)::operator new(cap * sizeof(T));
if (cap < pr_Size) {
pr_Size = cap;
}
for (size_t i = 0; i < pr_Size; i++) {
new(newBlock + i) T(std::move(pr_Array[i]));
}
for (size_t i = 0; i < pr_Size; i++) {
pr_Array[i].~T();
}
::operator delete(pr_Array, pr_Cap * sizeof(T));
pr_Array = newBlock;
pr_Cap = cap;
}
};
utils::list<int> list;
main() default-constructs an instance of this template. Let's inspect the template and its default constructor, then.
T* pr_Array;
size_t pr_Size;
size_t pr_Cap;
This template class declares these members.
list() {
The constructor does not have a member initialization section, and these three members do not have a default value, so all of these three class members are not initialized to anything. Their initial value is random garbage.
re_allocate(2);
The constructor then calls re_allocate(2).
if (cap < pr_Size) {
re_allocate, at this point, compares its parameter, cap, against pr_Size. But if you've been keeping careful notes, you will then note that pr_Size was not initialized to anything. From this point on, everything is undefined behavior.
There may or may not be additional instances of undefined behavior in this tempalte class, but given that this undefined behavior always occurs in the constructor, no further analysis is possible to determine that.
For example, pr_reallocate refers to pr_Array too. The current state of affairs is that pr_Array is also uninitialized and contains random garbage, so there's that as well. Whether or not this remains undefined behavior depends on how the initial occurence of undefined behavior gets fixed.
Then there's potential undefined behavior in the copy-constructor... But, one step at a time...
I am trying to create template classes for matrices and vectors of different sizes.
For my Vector class I overloaded the += and + operator to be able to add two vectors of same length. If lengths do not match I want the compiler to throw an error.
I want to store multiple of those mvc::Vector objects (with different lenghts) inside a std::vector.
To do that I created a base class mvc::VectorBase which I inherit all mvc::Vector objects from.
Now I can write
std::vector<std::unique_ptr<mvc::VectorBase>> vectorBuffer;
To be able to call member functions of MyVector from vectorBuffer I added pure virtual functions for those members so that I can use
vectorBuffer[0]->GetLength().
My problem: I can't write code like because VectorBase does not know the operator overload.
mvc::Vector<2> result = (*vectorBuffer[0]) + (*vectorBuffer[1]);
Trying to add operator overloading as pure virtual to mvc::VectorBase did not work because one argument would have to be a template argument from mvc::Vector template class, which I can´t use outside the template.
#include <vector>
#include <memory>
#define T float
namespace mvc
{
class VectorBase
{
public:
// virtual Vector operator+= (Vector<Tlength>& other) = 0;
virtual int GetLength() const = 0;
};
template<int Tlength>
class Vector : public VectorBase
{
private:
T vec[Tlength];
public:
Vector operator+ (Vector<Tlength>& other)
{
for (int i = 0; i < Tlength; i++)
{
vec[i] += other.vec[i];
}
return *this;
}
int GetLength() const
{
return Tlength
}
}
}
int main()
{
mvc::Vector<3> vec3_1;
mvc::Vector<3> vec3_2;
mvc::Vector<4> vec4_1;
mvc::Vector<3> result = vec3_1 + vec3_2; // this line works properly
mvc::Vector<3> result = vec3_1 + vec4_1; //this line won´t compile (as expected)
std::vector<std::unique_ptr<mvc::VectorBase>> vectorBuffer;
vectorBuffer.push_back(std::make_unique<mvc::Vector<2>>());
vectorBuffer.push_back(std::make_unique<mvc::Vector<2>>());
mvc::Vector<2> result = (*vectorBuffer[0]) + (*vectorBuffer[1]); // <-- this is what i want to be able to do
}
How do I implement the desired behavior?
vectorBuffer[0] + vectorBuffer[1] works ONLY if MyVector objects are generated with the same template (Tlength is equal)
This already works with two separately stored instances of MyVector.
It fails when I use polymorphism to store multiple mvc::Vector objects in the same std::vector.
EDIT:
By overloading + operator with with base class as return type I got the requested behavior:
#include <vector>
#include <memory>
#include <iostream>
#define T float
namespace mvc
{
class VectorBase
{
public:
virtual VectorBase* operator+ (VectorBase& other) = 0;
virtual int GetLength() const = 0;
virtual T GetElem(int i) const = 0;
virtual void Print() const = 0;
};
template<int Tlength>
class Vector : public VectorBase
{
private:
T vec[Tlength];
public:
Vector(T initValue)
{
for (int i = 0; i < Tlength; i++)
{
vec[i] = initValue;
}
}
VectorBase* operator+ (VectorBase& other) override
{
if (other.GetLength() != Tlength)
{
std::cout << "[Error]: Argument dimensions mismatch. Program will terminate." << std::endl;
std::cin.get();
exit(-1);
}
//Vector<Tlength> tmpOther = dynamic_cast<Vector<Tlength>&>(other);
for (int i = 0; i < Tlength; i++)
{
//vec[i] += tmpOther.vec[i];
vec[i] += other.GetElem(i);
}
return this;
}
Vector<Tlength> operator+ (Vector<Tlength>& other)
{
for (int i = 0; i < Tlength; i++)
{
vec[i] += other.GetElem(i);
}
return *this;
}
int GetLength() const override
{
return Tlength;
}
T GetElem(int i) const override
{
return vec[i];
}
void Print() const override
{
for (int i = 0; i < Tlength; i++)
{
std::cout << " " << vec[i] << "\n";
}
std::cout << std::endl;
}
};
}
int main()
{
/* without polymorphism */
// vector1
mvc::Vector<2> vec3_1 = mvc::Vector<2>(1.2f);
vec3_1.Print();
// vector2
mvc::Vector<2> vec3_2 = mvc::Vector<2>(3.4f);
vec3_2.Print();
// vector2 = vector1 + vector2
vec3_2 = vec3_1 + vec3_2;
vec3_2.Print();
/* with polymorphism */
// vector buffer storing base class objects
std::vector<mvc::VectorBase*> vectorBuffer;
//vector1
vectorBuffer.push_back(new mvc::Vector<3>(3.5f));
vectorBuffer[0]->Print();
//vector2
vectorBuffer.push_back(new mvc::Vector<3>(2.8f));
vectorBuffer[1]->Print();
//vector2 = vector1 + vector2
vectorBuffer[1] = *vectorBuffer[0] + *vectorBuffer[1];
vectorBuffer[1]->Print();
std::cin.get();
for (unsigned int i = 0; i < vectorBuffer.size(); i++)
{
delete vectorBuffer[i];
}
}
plus operator is overloaded twice to also support "non polymorphic" usage. (see example inside main)
Inside the operator+ override is a commend using #Vikas Awadhiya ´s dynamic_cast solution. This also works. Currently I do not know about performance compared to my current solution with virtual getter function GetElem.
For now I was only able to get it working with raw pointers. Still working on a unique_ptr solution.
Thanks for all replys!
You can do this by making your virtual operator+ return and accept the base class:
class VectorBase
{
public:
virtual int GetLength() const = 0;
// We have to return a heap allocated object because the actual type and,
// hence, its size is unknown
virtual std::unique_ptr<VectorBase> operator+(VectorBase& other) = 0;
};
template<int Tlength>
class Vector: public VectorBase
{
private:
// ...
std::unique_ptr<VectorBase> operator+(VectorBase& other) override
{
if (other.GetLength() != Tlength)
return nullptr; // or throw an exception if you want
Vector result = *this + static_cast<Vector<Tlength>&>(other);
// or "new Vector<Tlength>(result)" if your compiler doesn't support C++14
return std::make_unique<Vector<Tlength>>(result);
}
// ...
};
I have made few changes in code see this,
#include <iostream>
#include <vector>
#include <memory>
namespace mvc
{
class VectorBase
{
public:
virtual ~VectorBase(){}
virtual VectorBase& operator+ ( VectorBase& other) = 0;
virtual int GetLength() const = 0;
};
template<int length>
class Vector: public VectorBase
{
private:
double vec[length];
public:
Vector(): VectorBase(),
vec{}
{
}
VectorBase& operator+ ( VectorBase& other) override
{
Vector< length>& subOther = dynamic_cast< Vector< length>&>( other);
for ( int i = 0; i < length; i++)
{
vec[i] += subOther.vec[ i];
}
return *this;
}
int GetLength() const
{
return length;
}
};
}
int main()
{
std::vector<std::unique_ptr<mvc::VectorBase>> vectorBuffer;
vectorBuffer.push_back( std::make_unique<mvc::Vector< 2>>());
vectorBuffer.push_back( std::make_unique<mvc::Vector< 2>>());
mvc::Vector< 2> result = dynamic_cast< mvc::Vector< 2>&>( *vectorBuffer[ 0] + *vectorBuffer[ 1]);
std::cout<< "result.length = "<< result.GetLength()<< std::endl;
}
output: result.length = 2
I am just starting with C++. I am trying to design a class(interface) for a subset of vector operations. This Abstract Base Class is defined as:
//file: vect.hh
#ifndef _vect_hh
#define _vect_hh
class vect
{
public:
virtual double norm() const = 0;
virtual void add(const double scaleThis, const double scaleOther,
const vect& other) = 0;
virtual double dot(const vect& other) const = 0;
virtual vect* clone() const = 0;
virtual vect* copy(const vect& other) const = 0;
virtual ~vect()=default;
};
#endif
The problems appears in the functions that has as argument const vect& other. Since in the derived class what I really want is something like
const vectDerived& other as argument. To exemplify the problem I made a simple implementation of the previous class using raw pointers. Because I have some others problems that I going to comment at the end of this question I have inserted the full definition of the class. But keep in mind the most important functions are dot and add:
// file: vectDouble.hh
#ifndef _vectDouble_hh
#define _vectDouble_hh
#include <cmath>
#include <cstring>
#include "vect.hh"
class vectDouble: public vect
{
public:
explicit vectDouble(const int n): n{n}, elem{new double[n]}
{
std::memset(elem,'\0',sizeof(double)*n);
}
~vectDouble() override {delete[] elem;}
vectDouble(const vectDouble& other): n{other.n}, elem{new double[n]}
{
std::memcpy(elem, other.elem, n*sizeof(double));
}
vectDouble& operator=(const vectDouble& other)
{
if(&other != this){
delete[] elem; n = other.n;
elem = new double[n];
std::memcpy(elem, other.elem, sizeof(double)*n);
}
return *this;
}
vectDouble(vectDouble&& other): n{0}, elem{nullptr}
{
fillClass(other, *this);
}
vectDouble &operator=(vectDouble&& other)
{
if(&other != this){
delete[] elem;
fillClass(other, *this);
other.elem = nullptr; other.n = 0;
}
return *this;
}
double norm() const override
{
double norm = 0.0;
for(int i=0;i<n;i++){norm += elem[i]*elem[i];}
return std::sqrt(norm);
}
double dot(const vect& other) const override
{
const vectDouble &v = dynamic_cast<const vectDouble&>(other);
double dot = 0.0;
for(int i=0;i<n;i++){dot += elem[i]*v.elem[i];}
return dot;
}
void add (const double scaleThis, const double scaleOther,
const vect& other) override
{
const vectDouble &v = dynamic_cast<const vectDouble&>(other);
for(int i=0;i<n;i++){
elem[i] = scaleThis*elem[i] + scaleOther*v.elem[i];
}
}
double& operator[](const int i){return elem[i];}
const double& operator[](const int i) const {return elem[i];}
int size() const{return n;}
vectDouble* clone() const override
{
return new vectDouble(*this);
}
vectDouble* copy(const vect& other) const override
{
const vectDouble &v = dynamic_cast<const vectDouble&>(other);
auto *t = new vectDouble(*this);
t->n = v.n;
std::memcpy(t->elem, v.elem, t->n*sizeof(double));
return t;
}
private:
void fillClass(const vectDouble& in, vectDouble& out)
{
out.n = in.n; out.elem = in.elem;
}
int n;
double *elem;
};
#endif
In both functions I used const vectDouble &v = dynamic_cast<const vectDouble&>(other); to convert the base class reference to a reference with type of the derived class. This is a valid use case for the dynamic_cast. If not, what is the proper way to achieve this result?
I have remarked that I have run in other problems (sorry for straying away of the main question). As example of use of the abstract class and of the previous implementation I made this simple and somewhat contrived main program:
// file main.cc
#include <iostream>
#include <memory>
#include "vectDouble.hh"
double lsfit(const vect& dobs, const vect& dcalc)
{
std::unique_ptr<vect> tmp(dcalc.copy(dcalc));
return (dobs.dot(dcalc))/(dcalc.dot(*tmp));
}
void testFit()
{
vectDouble d{10};
vectDouble x{10};
for(int i=0;i<x.size();i++){
d[i] = static_cast<double>(3*i);
x[i] = static_cast<double>(i);
}
std::cout<<"alpha="<<lsfit(d, x)<<std::endl;
}
int main()
{
testFit();
return 0;
}
This program illustrate one use case envisioned for the interface described. However without the use of the std::unique_ptr there is a memory leak (identified using the option -fsanitize=leak from the g++compiler). If Instead of using the unique_ptr I wanted to manually manage the memory (as curiosity) what is the proper way to clean up this result? Is possible to return directly a std::unique_ptr from the copy function. When I tried to do this I received error messages relative to wrong covariant return types.
Remarks:
1) The intent of this interface is to abstract the storage scheme used to represent the arrays, for instance a file instead of an in memory representation.
2) I am aware that the copy function presented is more akin to create/clone plus copy function.
3) The structure presented is adequated if in the future I wanted to use templates in both the base and derived classes? For instance template<float> class vect{...} and template <float> class vectDerived{...}?
Following the advice of #hayt I have changed the definitions of both vect.hh and vectDouble.hh to use the CRTP pattern described. After these changes I also changed the definition of the function lsftit to:
template <class Derived> double lsfit2(const Derived& dobs, const Derived& dcalc)
{
std::unique_ptr<Derived> tmp = dcalc.clone();
Derived *t = tmp.get();
t->copy(dcalc);
return (dobs.dot(dcalc))/(dcalc.dot(*t));
}
Is this a proper way to define this function when using this pattern?
Thanks.
You should check if you really need inheritance and maybe switch to one generic vector class with a template parameter (from you only have "double" as something specific)
An alternative would be using CRTP in combination with declaring an interface. (I also added the unique_ptr in this apporach)
template <class Derived>
class vect
{
public:
virtual double norm() const = 0;
virtual void add(const double scaleThis, const double scaleOther,
const Derived& other) = 0;
virtual double dot(const Derived& other) const = 0;
virtual std::unique_ptr<Derived> clone() const = 0;
virtual std::unique_ptr<Derived> copy(const vect& other) const = 0;
virtual ~vect()=default;
};
This way you have the same "interface" but a different "base class" and you have the derived class also in your functions here. So you will not have to worry about assigning "incompatible" vectors to each other via the interfaces (see dynamic_cast).
Additionally you can later derive the class for further specifications.
Here is what you class would look like with this approach:
class vectDouble: public vect<vectDouble>
{
public:
//...
//NOTE: here vecDouble is a parameter. no need for dynamic casts
double dot(const vectDouble& other) const override
{
double dot = 0.0;
for(int i=0;i<n;i++){dot += elem[i]*other.elem[i];}
return dot;
}
void add (const double scaleThis, const double scaleOther,
const vectDouble& other) override
{
for(int i=0;i<n;i++){
elem[i] = scaleThis*elem[i] + scaleOther*other.elem[i];
}
}
//also directly a unique pointer
std::unique_ptr<vectDouble> clone() const override
{
return std::make_unique<vectDouble>(*this);
}
//...
};
I have class NumberArray in NumberArray.h
class NumberArray
{
private:
double *aPtr;
int arraySize;
public:
NumberArray(NumberArray &);
NumberArray(int size, double value);
NumberArray() { if (arraySize > 0) delete[] aPtr; }
void print() const;
void setValue(double value);
};
In my cpp file, NumberArray.cpp I define the constructor
NumberArray(NumberArray &)
by
NumberArray::NumberArray(NumberArray &obj)
{
arraySize = obj.arraySize();
aPtr = new double[arraySize];
for (int index = 0; index < arraySize; index++)
{
aPtr[index] = obj.aPtr[index];
}
}
From all I've learned, this should work. However I'm receiving an error "expression preceeding parenthesis of apparent call must have (pointer-to-) function type.
I thought I already did have a point-to function type...
Can someone help me with where I went wrong?
arraySize = obj.arraySize();
arraySize is a class member. It is not a class method. This should be:
arraySize = obj.arraySize;
I am porting this code from Visual C++ 6.0 (it also worked with an older GCC++) to Visual Studio 2010 C++. The code compiles but throws an exception.
I have an base class, CncMatchedQueryAtom. This class is used contain matches of different types of target atoms (this is a graph matching application) for 99% of the cases there is a one to one match between the query and the target. This is handled by the derived class, CncMatchedQueryAtomSimple. This class works great. The problem is that some query atoms match groups of atoms, this is handled by the class, CncMatchedQueryAtomGroup. This class contains a vector with the matched atoms. I want the iterator class defined within the base class to encapsulate the vector iterator in the derived class such that begin() returns the vector begin() and the end returns the vector's end().
The old version has problems on the end() at runtime because it does the conversion by:
return &*group.end();
Which is no longer allowed by Visual C++
So how can a base class specify an iterator that derived classes can implement? This doesn't seem very obvious to me, but I'm new to C++. Nor is it something that seasoned C++ developers that I work with know of either.
Basically, I want the base class to have methods that provide begin and end functions that the derived classes implement.
Here is the code:
class CncMatchedQueryAtom
{
protected:
int notBlockAllocated;
public:
int allocateIndividually() const
{
return notBlockAllocated;
}
const CncAtom *queryAtom;
CncAtom *queryAtomVolitile() const
{
return (CncAtom*)queryAtom;
}
// set when the class has been allocated by newing
// intialize all default constructors to be notBlockAllocated
CncMatchedQueryAtom()
: notBlockAllocated(1)
, queryAtom(NULL) // i don't think this needs to be initialized to null
{
}
CncMatchedQueryAtom(int noBlock)
: notBlockAllocated(noBlock)
, queryAtom(NULL) // i don't think this needs to be initialized to null
{
}
// may not need this now that it's a virtual!
CncMatchedQueryAtom(const CncMatchedQueryAtom &that)
: queryAtom(NULL)
{
*this = that;
}
// this needs to be virtual so when delete CncMatchedQueryAtom is called
// the virtual calss members are destructed too
virtual ~CncMatchedQueryAtom()
{
}
virtual void dump() const =0;
virtual void clearMapping() =0;
virtual CncMatchedQueryAtom *newCopy() const =0;
virtual void coverHits(class CncTarget *) const = 0;
// iterates over all matched target atoms for this query atom
class iterator
{
private:
CncMatchedTargetAtom *ptr;
public:
iterator()
{
}
iterator(const CncMatchedTargetAtom *targetAtom) // constructor from a target ptr
:ptr((CncMatchedTargetAtom *)targetAtom)
{
}
iterator(const iterator &oldOne)
:ptr(oldOne.ptr)
{
}
~iterator()
{
}
int operator==(const iterator &that) const
{
return ptr==that.ptr;
}
int operator!=(const iterator &that) const
{
return ptr!=that.ptr;
}
const CncMatchedTargetAtom &operator*() const
{
return *ptr;
}
iterator operator++(int NotUsed) // post increment
{
iterator returnValue(*this);
++ptr;
return returnValue;
}
iterator &operator++() // pre increment
{
++ptr;
return *this;
}
int operator<(const iterator &rhs) const
{
return (this->ptr < rhs.ptr);
}
CncMatchedTargetAtom *operator->()
{
return ptr;
}
};
virtual iterator begin() const =0;
virtual iterator end() const =0;
virtual int size() const = 0;
virtual double molecularWeight() const = 0;
const CncAtom *getFirstTargetAtom() const
{
return (*begin()).matchedTargetAtom;
}
CncAtom *getFirstTargetAtomVolitile() const
{
return (CncAtom*)getFirstTargetAtom();
}
}; // class CncMatchedQueryAtom
class CncMatchedQueryAtomSimple : public CncMatchedQueryAtom
{
public:
// we need a constructor here since this is allocated with blockAlloc
CncMatchedQueryAtomSimple()
: CncMatchedQueryAtom(0)
{
}
// we use simple.targetAtom as a temporary variable
// used to pass to matching functions
CncMatchedTargetAtom simple;
void clearIt()
{
queryAtom=NULL;
notBlockAllocated=0;
}
// if queryAtom is an element-type atom (or Lp or A atom)
void dump() const;
void clearMapping()
{
}
CncMatchedQueryAtom *newCopy() const
{
// since this is usually not allocatedIndividually I'll set
// the notBlockAllocatedFlag on the copy to be sure if this
// does happen it will individually deallocate it
CncMatchedQueryAtomSimple *retVal = new CncMatchedQueryAtomSimple(*this);
retVal->notBlockAllocated = 1;
return (CncMatchedQueryAtom *)retVal;
}
void coverHits(class CncTarget *) const;
iterator begin() const
{
return &simple;
}
iterator end() const
{
return &simple+1;
}
int size() const
{
return 1;
}
double molecularWeight() const
{
return CncMolGetAtomicMassAve(simple.matchedTargetAtom->getAtomicNumber());
}
}; // class CncMatchedQueryAtomSimple
class CncMatchedQueryAtomGroup : public CncMatchedQueryAtom
{
public:
// if queryAtom is an R- or X-group searching for
std::vector<CncMatchedTargetAtom> group;
void dump() const;
void clearMapping()
{
group.clear();
}
CncMatchedQueryAtom *newCopy() const
{
return new CncMatchedQueryAtomGroup(*this);
}
void coverHits(class CncTarget *) const;
iterator begin() const
{
return &*group.begin();
}
iterator end() const
{
// this is a hack, works with Visual C++ 6.0 and older GCC++ but not VS C++ 2010
return &*group.end(); // Throws error at runtime! Iterator Not Dereferencable
}
int size() const
{
return group.size();
}
double molecularWeight() const
{
double sum=0;
std::vector<CncMatchedTargetAtom>::const_iterator q;
for (q=group.begin()
; q!=group.end()
; ++q)
{
sum += CncMolGetAtomicMassAve(q->matchedTargetAtom->getAtomicNumber());
}
return sum;
}
}; // class CncMatchedQueryAtom
An example of how the iterator is called:
// Sample call to the iterator
// (*elem)->getMatchedAtom() returns a CncMatchedQueryAtom *
CncMatchedQueryAtom::iterator atomMatched;
// welp it looks like we have to do these
//(*elem)->getFirstTargetAtom
for (atomMatched=(*elem)->getMatchedAtom()->begin()
; atomMatched!=(*elem)->getMatchedAtom()->end() // Runtime exception here!
; ++atomMatched)
{
existenceFingerprint.setBit(
atomMatched->matchedTargetAtom->indexInStructure);
}
Thanks, hopefully this isn't too much code...
You cannot convert iterators from one container into iterators to another container.
It used to work with VC6, because they happened to use a pointer as vector::iterator. Later versions have an iterator class where the conversion does not work.