how can I assign an inherited method to an object?
, can you explain to me what is wrong with my code?
I am a newbie, so I would like to know if there is a better way to do it
int main(){
CalculateData data;
data = data.ReadData(data);//does not let me assign data to the method??
}
Rest of the code
#include<string>#include<fstream>#include<iostream>#include<vector>using namespace std;
class File//base class
{
private:
double Size;
public:
vector <double>values;
double GetSize();
void SetSize(double size);
File ReadData(File data);
};
class CalculateData :public File {//inherent from file class
public:
std::vector <double> value;
}
File File::ReadData(File file) {//method of File class
{std::fstream File("Data.txt", std::ios_base::in);
double a;
int counter = 0;
while (File >> a)
{
//printf("%f ", a);
file.values.push_back(a);
counter++;
}
file.SetSize(counter);
cout << "size is " << file.GetSize() << endl;
File.close();
}
return file;
}
Frankly, it is hard to help, because the error is just a consequence of a flawed approach. I'll use an example simpler than yours that has most of the same issues:
#include <iostream>
struct Base {
int value;
Base read(Base b) {
b.value = 42;
return b;
};
};
struct Derived : Base{
int values;
};
int main() {
Derived d;
d = d.read(d);
}
The immediate problem is the compiler error:
<source>: In function 'int main()':
<source>:17:17: error: no match for 'operator=' (operand types are 'Derived' and 'Base')
17 | d = d.read(d);
| ^
<source>:11:8: note: candidate: 'constexpr Derived& Derived::operator=(const Derived&)'
11 | struct Derived : Base{
| ^~~~~~~
<source>:11:8: note: no known conversion for argument 1 from 'Base' to 'const Derived&'
<source>:11:8: note: candidate: 'constexpr Derived& Derived::operator=(Derived&&)'
<source>:11:8: note: no known conversion for argument 1 from 'Base' to 'Derived&&'
d is a Derived and read returns a Base. They are different types, you cannot assign them to each other unless you provide some conversion between them.
However, it does not make sense that read takes a Base as argument (by value) and returns that just to let the caller assign it to the object they called the method on. If the method is intended to modify the current object then it should do so directly:
void read() {
value = 42;
}
There is absolutely no need to pass a Base as argument, which will be copied anyhow, because you pass it by value.
The next thing that is fishy in the code is that Derived has another member which is similar named as the one of Base but unused. Derived already does inherit the value member from Base. It does not need another values member.
Last but not least, initialization of members should take place in the initializer list of the constructor (if not in-class initializers are used). If initialization is complicated a static method can be used. Hence:
struct Base {
int value;
Base() : value( read_input() ) {}
static int read_input() {
return 42;
}
};
struct Derived : Base {};
int main() {
Derived d;
}
This code does the same as the above. As it is not clear what the purpose of Derived is, it can be removed.
Related
Can I pass the method as a pointer to some function that accepts the base class method pointer?
Like here, function tryit accepts two parameters with class Object. There should be polymorphism, but the compiler throws an error.
#include <iostream>
using namespace std;
class Object {
};
class Derived : public Object
{
private:
public:
void printit() {
cout << "Ok" << endl;
}
};
void tryit(Object* obj, void (Object::*fn)() ) {
(obj->*fn)();
}
int main() {
Derived d;
tryit(&d, &Derived::printit);
}
Compiler says this:
main.cc: In function ‘int main()’:
main.cc:31:15: error: cannot convert ‘void (Derived::*)()’ to ‘void (Object::*)()’
31 | tryit(&d, &Derived::printit);
| ^~~~~~~~~~~~~~~~~
| |
| void (Derived::*)()
main.cc:24:25: note: initializing argument 2 of ‘void tryit(Object*, void (Object::*)())’
24 | void tryit(Object* obj, void (Object::*fn)() ) {
| ^~~~~~~~~~~~~~~~~~~~
I don't want to use virtual methods in Object class, because I want to be able to call function with various names.
This works:
typedef void (Object::*memfn)();
tryit(&d, (memfn) &Derived::printit);
But why this is not converted implicitly, why do I need to cast it manually?
Unfortunately, polymorphism doesn't work this way. Member-pointers of derived classes are not implicitly convertible to member-pointers of parent classes. Only pointers (and references) to derived class objects are implicitly convertible to pointers to parent class objects.
You can cast your pointer, and make compiler happy:
int main() {
Derived d;
tryit(&d, static_cast<void (Object::*)()>(&Derived::printit));
}
Thanks to #StoryTeller-UnslanderMonica for digging, there seems to be an explicit blessing in Standard:
https://timsong-cpp.github.io/cppwp/n4868/expr.static.cast#12
Using virtual is the legal and safe way to handle this for polymorphic types. Your claim that you don't want to use virtual because you "want to be able to call function with various names" makes no sense.
But, if you really don't want to use virtual then consider making tryit() a template function instead, eg:
template<typename T>
void tryit(T* obj, void (T::*fn)() ) {
(obj->*fn)();
}
int main() {
Derived d;
tryit(&d, &Derived::printit);
}
Alternatively:
template<typename Callable>
void tryit(Callable fn) {
fn();
}
int main() {
Derived d;
tryit([&](){ d.printit(); });
}
Or, you can use std::function without a template, eg:
void tryit(std::function<void()> fn) {
fn();
}
int main() {
Derived d;
tryit([&](){ d.printit(); });
}
But why this is not converted implicitly, why do I need to cast it manually?
Because it's one of those conversions where you have to tell the compiler you posses extra knowledge that guarantees it's safe. Take object pointers for instance:
struct A { int x; };
struct B : A { char c; };
A *pa = new B();
auto pb = static_cast<B*>(pa);
Converting a B* to an A* is implicit. It's an unambiguous base class. The compiler knows there is an A object in that B and can just go ahead with it. But the converse is not true, you must cast it (employing your extra knowledge) to let it know that that A* is really pointing at a B*.
Pointers to members are the same in a way.
int B::* pmb = &A::x;
auto pma = static_cast<char A::*>(&B::c);
pa->*pma = 'c';
Obtaining a pointer to a member of B from a pointer to a member of A is an implicit conversion. The same knowledge about B containing an A (and therefore the member x) is available to the compiler. But it cannot assume the converse willy-nilly. What if the object pointer pa is not really pointing at a B? Accessing that "member of B" would be disastrous then.
By the same reasoning as before, you need a cast to let the compiler know you have extra knowledge about the actual derived object type.
Consider the following. Class A has a function pointer as a member and accepts a function in its constructor to pass to this member. In a separate file, I have a class B that contains a pointer to class A as a member, and class B also has as a member the function I want to pass to class A.
Below is an example and the errors I receive. What's the standard method of doing something like this?
A.h:
class A {
private:
int (*func)(int);
public:
A(int (*func_)(int));
};
A::A(int (*func_)(int)) : func(func_) {}
B.h:
#include "A.h" // Why can't I forward declare A instead?
class B {
private:
A *A_ptr;
int function(int); // some function
public:
B();
~B();
};
int B::function(int n) {
return n+2; // some return value
}
B::B() {
A_ptr = new A(function);
}
B::~B() {
delete A_ptr;
}
main.cpp:
#include "B.h"
int main() {
B b;
}
Errors I get:
B.h: In constructor ‘B::B()’:
B.h:18:25: error: no matching function for call to ‘A::A(<unresolved overloaded function type>)’
B.h:18:25: note: candidates are:
A.h:9:1: note: A::A(int (*)(int))
A.h:9:1: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘int (*)(int)’
A.h:1:7: note: A::A(const A&)
A.h:1:7: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘const A&’
To answer your question regarding "What's the standard method of doing something like this" I'll assume you mean passing member functions and/or general function pointers around and executing them with some data. Some popular implementations which provide this ability are:
FastDelegate
std::function
boost::function
It really comes down to preference and library choice. Personally, I've used FastDelegate most of the time and then std::function after that.
All the links I posted should have tutorial information to get you up and running and show you how to properly pass and store member functions and/or general function pointers with ease.
Here's an example of using a FastDelegate with your example:
class A
{
public:
// [1] This creates a delegate type. Can used for any function,
// class function, static function, that takes one int
// and has a return type of an int.
typedef FastDelegate1< int, int > Delegate;
// [2] Pass the delegate into 'A' and save a copy of it.
A( const Delegate& delegate ) : _delegate( delegate ) { };
void execute()
{
// [7]
// Result should be 10!
int result = _delegate( 8 );
}
private:
// [3] Storage to save the Delegate in A.
Delegate _delegate;
};
class B
{
public:
B()
{
// [4] Create the delegate
A::Delegate bDelegate;
bDelegate.bind( this, &B::function );
// [5] Create 'A' passing in the delegate.
_aPtr = new A( bDelegate );
// [6] Test it out!! :)
// This causes `A` to execute the Delegate which calls B::function.
_aPtr->execute();
}
~B()
{
delete _aPtr;
}
int function( int n )
{
return n+2;
}
private:
A* _aPtr;
};
I have two versions of a C++ code. One give the problem and other does not:
/*
* This compiles fine
*/
class base {
private:
const char c;
};
int main() {
base b(); // compiles fine
}
/*
* This gives compilation error
*/
class base {
private:
const char c;
};
int main() {
base b; // error: structure 'b' with uninitialized const members
}
Note the difference is 'base b()' and 'base b'.
I thought that both will call default constructor and since the class has a const field, the program will fail to compile.
Please help to explain this.
That is because the first version does not create an object of type base, but rather declares a function called b which takes no argument and returns an object of type base:
base b; // Declares an object b of type base
base b(); // Declares a FUNCTION called b that takes no argument an returns a base
In fact, you could try the following to verify that this is indeed the case:
int main() {
base b(); // DECLARES function b()
b(); // INVOKES function b()
}
base b() // DEFINITION of function b()
{
base c;
// ...
return c;
}
Now function main() won't give you problems anymore, but the base c; inside the b() function will. Exactly like the base b; in your original example. Why?
Well, because in general data members whose type is const-qualified should be initialized as soon as you construct the object (just like data members of a reference type). A way to guarantee this in general is to initialize those data members in the constructor's initialization list.
This, for instance, will compile:
class base {
public:
base() : c('x') { }
private:
const char c;
};
int main() {
base b;
}
const char c; Must be defined when declared.
const char c = 'a'; for example
When I try to compile the following code:
class A {
public:
A(int v) : virt(v) { }
int virt;
int getVirt(void) const { return virt; }
};
class B : private virtual A {
protected:
B(int v) : A(v) { }
using A::getVirt;
};
class C : public B, private virtual A {
protected:
C(int v) : A(v), B(v) { }
using A::getVirt;
};
class D : public C {
public:
D(void) : C(3) { }
using C::getVirt;
};
#include <iostream>
int main(int argc, char *argv[]) {
D d;
std::cout << "The number is: " << d.getVirt() << std::endl;
return 0;
}
I get an error about D not instantiating A; is that correct? If a virtual base is embedded in the hierarchy do all derived classes also need to derive from that base, virtually, so they can call the parametric constructor of the virtual base?
BTW, here are the errors produced by G++:
Main.cpp: In constructor ‘D::D()’:
Main.cpp:22:18: error: no matching function for call to ‘A::A()’
Main.cpp:22:18: note: candidates are:
Main.cpp:3:5: note: A::A(int)
Main.cpp:3:5: note: candidate expects 1 argument, 0 provided
Main.cpp:1:7: note: A::A(const A&)
Main.cpp:1:7: note: candidate expects 1 argument, 0 provided
That has nothing to do with access control (at least not primarily). Rather, you have to understand how virtual bases work: The virtual base subobject is initialized by the most derived class. Since you don't mention A in the constructor initializer list of D, the default constructor is tried, but doesn't exist.
To fix this, initalize A properly in D:
D() : A(3), C(3) { }
When you say A(3), name lookup is performed according to 12.6.2/2:
In a mem-initializer-id an initial unqualified identifier is looked up in the scope of the constructor’s class and, if not found in that scope, it is looked up in the scope containing the constructor’s definition.
As Drew Dorman rightly points out, you can force a direct path to the virtual base class by calling it ::A and thus obtaining the desired access.
As Kerrek SB mentions, you need to initialize A in the constructor for D.
However, you must also explicitly tell the compiler that you are not accessing A from its (privately) derived context by using the scope operator.
class D : public C {
public:
D(void) : ::A(3), C(3) { }
// ^^ Access this constructor from a global context
using C::getVirt;
};
This also means that your constructor must be public, as is already the case with your code.
From what I understand about inheritance in C++ is that whenever the constructor of a child class is called, constructor of the parent class is called automatically. And as for templated constructors, data type of the template argument is infered automatically i.e. we don't need to specify template arguments separately. The program generates a compilation error which I don't seem to understand.
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class A{
public:
int x;
int y;
int first(){
return x;
}
int second(){
return y;
}
};
class C{
public:
float a,b;
C(){
a = 0.0f;
b = 0.0f;
}
template<class T>
C(T t){
a = t.first();
b = t.second();
}
};
class D: public C{
public:
float area(){
return a*b;
}
}
int main(){
A a;
a.x = 6;
a.y = 8;
C c(a);
D d(a);
cout<<c.a<<" "<<c.b<<" "<<d.area()<<endl;
}
Compilation error generated
test.cpp: In function ‘int main()’:
test.cpp:56:8: error: no matching function for call to ‘D::D(A&)’
test.cpp:56:8: note: candidates are:
test.cpp:44:7: note: D::D()
test.cpp:44:7: note: candidate expects 0 arguments, 1 provided
test.cpp:44:7: note: D::D(const D&)
test.cpp:44:7: note: no known conversion for argument 1 from ‘A’ to ‘const D&’
I have no idea what is happening here. Any ideas?
D has to pass the constructor argument to C, since you are not using default constructors.
class D : public C {
public:
template <typename T> D (T t) : C(t) {}
float area () { /* ... */ }
};
The reason for the error is that you are trying to construct D with a parameter, but have not declared any constructor that would allow you to do so. Furthermore, you have to pass the parameter into C, otherwise the compiler will use C's default constructor.
The compiler error message can be analyzed like this.
test.cpp:56:8: error: no matching function for call to ‘D::D(A&)’
The compiler is complaining about:
D d(a);
And that it can't figure out how to construct a D when passed something of type A.
It then presents the two choices of constructors it knows about:
test.cpp:44:7: note: D::D()
test.cpp:44:7: note: D::D(const D&)
And it points out that for each one, there is a reason it can't use it. For the first one, it doesn't take any arguments. For the second one, it has no way to convert something of type A into type D.
From what I understand about inheritance in C++ is that whenever the constructor of a child class is called, constructor of the parent class is called automatically.
Careful: The constructor of the parent class is automatically called with the same arguments as the constructor of the child class.
As for the specific problem at hand: There is no constructor declared for class D. You'll get a default constructor and copy constructor as freebies, but not that template-based constructor in class C. Constructors aren't inherited.