I'm using the ROOT frameowrk and I want to write a class the has a TMultiGraph member. I'm trying to write and assignment operator for my class but I fail due to compilaton issues. The class TMultiGraph keeps it's assignment operator as protected.
The header for my class:
#include "../include/clipper.hpp"
#include "TMultiGraph.h"
#include "TColor.h"
#include "RtypesCore.h"
using namespace ClipperLib;
class ClipperDraw : protected TMultiGraph {
public:
ClipperDraw() {}
ClipperDraw& operator=(const ClipperDraw &c);
private:
TMultiGraph mg;
};
The .cpp is:
ClipperDraw& ClipperDraw::operator=(const ClipperDraw &c)
{
mg = c.mg;
return *this;
}
When compiling I get this message:
g++ -fPIC -Wall `root-config --cflags` -I./include -O2 -c -o obj/ClipperDraw.o src/ClipperDraw.cpp
In file included from src/../include/ClipperDraw.h:12:0,
from src/ClipperDraw.cpp:8:
/home/user/anaconda3/envs/deepjetLinux3/include/TMultiGraph.h: In member function ‘ClipperDraw& ClipperDraw::operator=(const ClipperDraw&)’:
/home/user/anaconda3/envs/deepjetLinux3/include/TMultiGraph.h:47:17: error: ‘TMultiGraph& TMultiGraph::operator=(const TMultiGraph&)’ is protected
TMultiGraph& operator=(const TMultiGraph&);
^
src/ClipperDraw.cpp:26:5: error: within this context
mg = c.mg;
^
Makefile:19: recipe for target 'obj/ClipperDraw.o' failed
make: *** [obj/ClipperDraw.o] Error 1
The copy constructor and the copy assignment operator for TMultiGraph are both marked as protected. That means you cannot assign a TMultiGraph to another TMultiGraph. Inheritance won't help you as it doesn't change that fact.
What inheriting from TMultiGraph will do is allow to to make your own graph class that you can copy. That would look like
class MyMultiGraph : public TMultiGraph {
//...
public:
MyMultiGraph& operator =(const MyMultiGraph& rhs)
{
TMultiGraph::operator=(rhs);
// assign MyMultiGraph member here
}
};
Related
Please have a look at directory structure first [ attached at the bottom of the question end].
Following are my Cmake files :
Main cmake
cmake_minimum_required(VERSION 3.9)
set (CMAKE_CXX_STANDARD 14)
add_executable (test main.cc)
target_include_directories(test PUBLIC test_include_interface)
target_link_libraries(test PUBLIC test_test)
Test cmake :
add_library(test_include_interface INTERFACE)
target_include_directories(test_include_interface INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
add_library(test_test STATIC test_interface.h
test.h
test.cc)
target_include_directories(test_test INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
test.h
#pragma once
#include "test_interface.h"
#include <memory>
class Test : public ITest {
public:
Test();
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
test.cc
#include "test.h"
class Test::Impl {
public:
Impl() {}
~Impl() {}
};
Test::Test() : impl_{std::make_unique<Impl>()} {}
Error :
In file included from /usr/include/c++/9/memory:80,
from /home/vkd0726/test/test/test.h:9,
from /home/vkd0726/test/main.cc:2:
/usr/include/c++/9/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Test::Impl]’:
/usr/include/c++/9/bits/unique_ptr.h:292:17: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Test::Impl; _Dp = std::default_delete<Test::Impl>]’
test/test/test.h:11:7: required from here
/usr/include/c++/9/bits/unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘Test::Impl’
79 | static_assert(sizeof(_Tp)>0,
| ^~~~~~~~~~~
make[2]: *** [CMakeFiles/test.dir/build.make:63: CMakeFiles/test.dir/main.cc.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/test.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
Please help me understand this error and how to resolve it ? Is it a problem with the Cmake or code itself. I have seen such "Impl" design pattern use at many places but unable to write a test snippet. What is wrong here ?
Directory structure
The Test does not contain a user defined destructor, so the compiler generates a inlined version of this destructor. Since this destructor involves logic to delete the Test::Impl object when the destructor of std::unique_ptr<Test::Impl> is invoked, you get the error your compiler complains about.
You can fix this by defining the destructor in test.cc:
test.h
#include <memory>
class Test : public ITest {
public:
Test();
~Test(); // new
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
test.cc
class Test::Impl {
...
};
...
Test::~Test() = default;
This is a common problem faced with std::unique_ptr for pimpl. The primary approach would be - as #fabian mentioned - to provide a declaration fir the nesting class's destructor and define it in the same translation unit as the pimpl implementation (most probably as a defaulted function). But this approach might disable some corner case optimizations, due to compiler not being able to deduce the triviality of the destructor of nesting class(Test according to OP). Another approach would be to provide a deleter class for the std::unique_ptr and leave the nesting class`s destructor intact:
class test{
public:
test();
private:
class impl;
struct deleter{
void operator(impl *)const;
};
std::unique_ptr<impl, deleter> up_impl;
};
Now define the deleter's function call operator in the same translation unit as impl to:
void test::deleter::operator(test::impl * ptr) const
{ delete ptr; };
This looks a little more work. But it pays off with an implicitly defined destructor. It also better suits the rule of 0/3/5.
I am trying to figure out where I am going wrong with creating variables from a derived class. I have the abstract class, the derived class and am trying to create the derived class as a variable in the main testing program. However I get the error: no matching function for call to DerivedPlayer::DerivedPlayer()’. I haven't been able to find the correct syntax as to create and initialize a variable of the derived class. Also note that the abstract class's constructor is protected.
Abstract Header (Base.h)
#ifndef BASE_H_
#define BASE_H_
#include <iostream>
#include <vector>
class Base {
public:
virtual ~Base() {}
protected:
Base(std::string s) : x(0), s(s), v(0) {}
int x;
std::string s;
std::vector<int> v;
};
#endif
Derived Header (Derived.h)
#ifndef DERIVED_H_
#define DERIVED_H_
#include "Base.h"
class Derived : public Base {
public:
Derived(std::string name){ s = name; }
virtual ~Derived();
};
#endif
Test Code (InTest.cpp)
#include <iostream>
#include "Derived.h"
int main() {
Derived a = Derived("R2-D2");
Derived b = Derived("C-3PO");
return 0;
}
Build Log
03:23:52 **** Incremental Build of configuration Debug for project InTest ****
make all
Building file: ../src/InTest.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/InTest.d" -MT"src/InTest.o" -o "src/InTest.o" "../src/InTest.cpp"
In file included from ../src/InTest.cpp:2:0:
../src/Derived.h: In constructor ‘Derived::Derived(std::string)’:
../src/Derived.h:8:27: error: no matching function for call to ‘Base::Base()’
Derived(std::string name){ s = name; }
^
../src/Derived.h:8:27: note: candidates are:
In file included from ../src/Derived.h:4:0,
from ../src/InTest.cpp:2:
../src/Base.h:12:2: note: Base::Base(std::string)
Base(std::string s) : x(0), s(s), v(0) {}
^
../src/Base.h:12:2: note: candidate expects 1 argument, 0 provided
../src/Base.h:7:7: note: Base::Base(const Base&)
class Base {
^
../src/Base.h:7:7: note: candidate expects 1 argument, 0 provided
make: *** [src/InTest.o] Error 1
03:23:52 Build Finished (took 214ms)
Here's the main part of the error message:
../src/Derived.h: In constructor ‘Derived::Derived(std::string)’:
../src/Derived.h:8:27: error: no matching function for call to ‘Base::Base()’
Derived(std::string name){ s = name; }
Because Derived inherits from Base, each time a Derived object is constructed the Base class constructor also have to run. The problem with your current code is that you let the default Base constructor be called, but there isn't any.
You solve it by "calling" the correct Base constructor in the Derived constructor initializer list:
Derived::Derived(std::string name)
: Base(name)
{}
I have the following code with two levels of inheritance of class templates:
template <typename FIELD>
class Class1
{
protected:
int n;
FIELD data1;
public:
Class1();
virtual ~Class1() {}
};
template <typename FIELD> class Class3;
template <typename FIELD>
class Class2 : public Class1<FIELD>
{
protected:
using Class1<FIELD>::n;
FIELD data2;
public:
Class2();
virtual ~Class2() {}
int Method(Class3<FIELD> &) const;
};
template <typename FIELD>
class Class3 : public Class2<FIELD>
{
protected:
using Class1<FIELD>::n;
FIELD data3;
public:
Class3();
virtual ~Class3() {}
};
template <typename FIELD>
int Class2<FIELD> :: Method(Class3<FIELD> & U) const
{
U = Class3<FIELD>();
int g = U.n;
return g;
}
template class Class2<double>;
I compile this into an object file in Ubuntu using command:
g++ -c -std=c++11 -Wall -Wfatal-errors -o Test.o Test.cpp
and no error whatsoever is generated, the object file is created just fine!
However, when I try to compile the very same code from within Visual Studio using Ctrl+F7, I get C2248 error that reads:
'Class3::n': cannot access protected member declared in class 'Class3'
Is there a bug in one of the compilers? Which one follows standard? Despite my faith in g++, I'm inclined to think that VS is more correct in this case since variable n should be accessed by Class2 only from Class1 (since it is base class for Class2) but not from Class3.
Note that I need to add line friend int Class2::Method(Class3<FIELD> &) const;
within Class3 declaration to bypass C2248 error in VS.
Thanks for all the answers!
I'm programming in c++ using sublimetext3. My program has a superclass called Array, and a subclass called IntArray. Both classes are template classes. Currently, I'm having trouble compiling the program. It keeps giving me an error in my IntArray.cpp file, specifically in my base class's constructor where I call and initialize the superclass's constructor with the parameter of the base class's constructor. I'm not sure how to call a superclass's template constructor from a subclass's template constructor. The error message is shown below. Also, below the error message are my source code files for main.cpp, Array.cpp, Array.h, IntArray.cpp, IntArray.h, and Makefile. The program is not yet complete. I currently only have one method that gets the size of the array.
Error message from terminal:
IntArray.cpp:4:56: error: member initializer 'Array' does not name a non-static data member or base class
template<class T> IntArray<T>::IntArray(T s) throw() : Array(s) {
^~~~~~~~
1 error generated.
main.cpp
#include <iostream>
#include <string>
#include "Array.h"
#include "IntArray.h"
int main(int argc, char** argv) {
// make an array of doubles with size 10
Array<int> iA(10);
// get the size of the array
std::cout<< "The size of IntArray is" <<iA.getSize()<<std::endl;
} // end of main
Array.cpp
#include "Array.h"
// constructor
template<class T> Array<T>::Array(T s) throw() {
size = s;
}
// destructor
template<class T> Array<T>::~Array() throw() {
}
// getter methods
template<class T> T Array<T>::getSize() const throw() {
return size;
}
Array.h
#ifndef ARRAY_H
#define ARRAY_H
template<class T> class Array {
private:
T size;
public:
Array(T s) throw();
virtual ~Array() throw();
// getter methods that throws an exception if the index is out of bounds
T getSize() const throw();
// setters that throws an exception if the index is out of bounds
};
#endif
IntArray.cpp
#include "IntArray.h"
// constructor
template<class T> IntArray<T>::IntArray(T s) throw() : Array(s) {
}
// desctructor
template<class T> IntArray<T>::~IntArray() throw() {
}
IntArray.h
#ifndef INTARRAY_H
#define INTARRAY_H
#include "Array.h"
template<class T> class IntArray : public Array<T> {
public:
IntArray(T s) throw();
virtual ~IntArray() throw();
//int getSize() const throw();
};
#endif
Makefile
all:main
main.o: main.cpp Array.h IntArray.h
g++ -c -Werror main.cpp
Array.o: Array.cpp Array.h
g++ -c -Werror Array.cpp
IntArray.o: IntArray.cpp IntArray.h
g++ -c -Werror IntArray.cpp
main: main.o Array.o IntArray.o
g++ -o main main.o Array.o IntArray.o
Use
template <class T> IntArray<T>::IntArray(T s) throw() : Array<T>(s) {}
// ^^^ Use <T>
More importantly, put the implemetation also in the .h file.
See Why can templates only be implemented in the header file?.
Other Issues I Noticed
It does not make sense that you are using T s for size. std::size_t s makes more sense.
It does not make sense that IntArray is a class template. It makes more sense to me to use:
class IntArray : public Array<int> { ... };
Hello I have upgraded my Xcode to version 4.2 and clang++ to version:
Apple clang version 3.0 (tags/Apple/clang-211.10.1) (based on LLVM 3.0svn)
Target: x86_64-apple-darwin11.2.0
Thread model: posix
When try to compile the following code with clang -std=c++0x
#include <memory>
#include <limits>
#include <boost/shared_ptr.hpp>
class ilpConstraintImpl {
public:
virtual ~ilpConstraintImpl() {}
};
class ilpConstraint {
public:
ilpConstraint(ilpConstraintImpl* implptr):impl(implptr) { }
public:
boost::shared_ptr<ilpConstraintImpl> impl;
};
class ilpExprImpl {
public:
virtual ilpConstraint operator<= (const double rs)=0;
virtual ~ilpExprImpl() {}
};
class ilpExpr {
public:
virtual ~ilpExpr() {};
ilpConstraint operator<= (const double rs) { return impl->operator<=(rs); }
ilpExpr(ilpExprImpl* implptr):impl(implptr) { }
boost::shared_ptr<ilpExprImpl> impl;
};
I get the following error:
./test.h:46:54: error: call to deleted constructor of 'ilpConstraint'
ilpConstraint operator<= (const double rs) { return impl->operator<=(rs); }
^~~~~~~~~~~~~~~~~~~~
./test.h:28:7: note: function has been explicitly marked deleted here
class ilpConstraint {
^
1 error generated.
Compiling without -std=c++0x works.
This looks like a clang bug to me. I'm working with a later clang version which does not have this behavior. You might try giving ilpConstraint an explicit copy constructor as a temporary workaround.
With C++0x support the boost smart pointers define move constructors. This however disables implicit copying by the automatically generated copy constructor and assignment operator.
There is a patch for boost's smart pointers which refits the copy constructors and the assignment operators if the support for C++0x is detected.
It can be found here: https://svn.boost.org/trac/boost/changeset/73202
I ran into the same problem, when one of the members of my class, didn't have a default constructor anymore.
struct OrderContact {
std::string name;
std::string phone;
OrderContact() {} // error without this constructor
OrderContact(std::string contactName, std::string contactPhone) : name(contactName), phone(contactPhone) {
}
};
class Order {
public:
OrderContact contact;
}