mardi 6 mai 2014

classe - classes en c ++ et virtuel funct - Stack Overflow


I want to create 2 kind of classes. the classes will have similar function "set", but the set funct will get "int" in class B and double in class C. (A is abstract calss but it does not require). What do I need to do?


class A{
int x;
public:
A (int t=1): x(t){}
virtual void set ()=0;
}

class B: public A{
int y;
public:
virtual void set (int y);
};

class C: public A{
double y;
public:
virtual void set (double y);
};

void main ()
{
B b; //error
C c; //error
}



Create a single template class and instantiate which ever you need at the time, or typedef B and C from the template class:


template< typename T > class A
{
public: A() : mValue() {}

void Set( T value ) { mValue = value; }

private: T mValue;
};

typedef A< int > B;
typedef A< double > C;



There are pretty many variants to solve this, but first of all, virtual function has to have the same signature (there could be an exception, but that's irrelevant for your case). So solution is to have and argument(s) that will solve all cases. There are variants:


Pass all variants to the function, and use only particular one:


class A {
public:
virtual void set( int, double ) = 0;
};
class B {
int y;
public:
virtual void set( int val, double ) { y = val; }
};
class C {
double y;
public:
virtual void set( int , double val ) { y = val; }
};

This is not very good solution and does not scale well, so we can use union:


Union Arg {
int i;
double d;
};

class A {
public:
virtual void set( Arg a ) = 0;
};
// derived classes are trivial, so omitted

Union is not type safe, so we can use boost::variant instead


Another solution to have another hierarchy for parameter:


struct Arg {
virtual ~Arg();
};
struct IntArg : Arg {
int m_value;
};
struct DoubleArg : Arg {
double m_value;
};
class A {
virtual void set( const Arg &a ) = 0;
};
class B {
int y;
public:
virtual void set( const Arg &a ) { y = dynamic_cast<const IntArg &>( a ).m_value; }
};
class C {
double y;
public:
virtual void set( const Arg &a ) { y = dynamic_cast<const DoubleArg &>( a ).m_value; }
};

You can use static_cast and then you will not need virtual destructor in Arg, but that is less safe.


These are only some variants, there could be much more, which one suits you best you can only decide based on your program requirements.




Ditch the inheritance and virtual thing. You can't easily access a statically unknown type result via a virtual function. So:


class A
{
private:
int x_;
public:
A( int const t = 1 ): x_( t ) {}
};

class B
: public A
{
private:
int y_;
public:
void set( int const y );
};

class C
: public A
{
private:
double y_;
public:
void set( double const y );
};

int main ()
{
B b; // OK
C c; // OK
}

Note the semicolon at the end of class A and the int main instead of void main.


Such details matter.


Otherwise you can send people who want to help you, on long wild goose chases. And you don't want that, do you? So, make sure the code you post has been accepted by a compiler, except possibly for the troublesome parts that you want to show do not compile.




The trick is to find common parts of B and C, and put them to base class. The stuff that is different should go to constructor parameter of the derived class:


class A { 
virtual std::string get() const=0;
virtual void set(std::string s)=0;
};
class B : public A { B(int a) : a(a) { } int a; };
class C : public A { C(float b) : b(b) { } float b; }

To implement the functions, you'll need the following:


void B::set(std::string s) {
stringstream ss(s);
ss >> a;
}
void C::set(std::string s) {
stringstream ss(s);
ss >> b;
}

The functions look the same, but are actually calling different operator>>.



I want to create 2 kind of classes. the classes will have similar function "set", but the set funct will get "int" in class B and double in class C. (A is abstract calss but it does not require). What do I need to do?


class A{
int x;
public:
A (int t=1): x(t){}
virtual void set ()=0;
}

class B: public A{
int y;
public:
virtual void set (int y);
};

class C: public A{
double y;
public:
virtual void set (double y);
};

void main ()
{
B b; //error
C c; //error
}


Create a single template class and instantiate which ever you need at the time, or typedef B and C from the template class:


template< typename T > class A
{
public: A() : mValue() {}

void Set( T value ) { mValue = value; }

private: T mValue;
};

typedef A< int > B;
typedef A< double > C;


There are pretty many variants to solve this, but first of all, virtual function has to have the same signature (there could be an exception, but that's irrelevant for your case). So solution is to have and argument(s) that will solve all cases. There are variants:


Pass all variants to the function, and use only particular one:


class A {
public:
virtual void set( int, double ) = 0;
};
class B {
int y;
public:
virtual void set( int val, double ) { y = val; }
};
class C {
double y;
public:
virtual void set( int , double val ) { y = val; }
};

This is not very good solution and does not scale well, so we can use union:


Union Arg {
int i;
double d;
};

class A {
public:
virtual void set( Arg a ) = 0;
};
// derived classes are trivial, so omitted

Union is not type safe, so we can use boost::variant instead


Another solution to have another hierarchy for parameter:


struct Arg {
virtual ~Arg();
};
struct IntArg : Arg {
int m_value;
};
struct DoubleArg : Arg {
double m_value;
};
class A {
virtual void set( const Arg &a ) = 0;
};
class B {
int y;
public:
virtual void set( const Arg &a ) { y = dynamic_cast<const IntArg &>( a ).m_value; }
};
class C {
double y;
public:
virtual void set( const Arg &a ) { y = dynamic_cast<const DoubleArg &>( a ).m_value; }
};

You can use static_cast and then you will not need virtual destructor in Arg, but that is less safe.


These are only some variants, there could be much more, which one suits you best you can only decide based on your program requirements.



Ditch the inheritance and virtual thing. You can't easily access a statically unknown type result via a virtual function. So:


class A
{
private:
int x_;
public:
A( int const t = 1 ): x_( t ) {}
};

class B
: public A
{
private:
int y_;
public:
void set( int const y );
};

class C
: public A
{
private:
double y_;
public:
void set( double const y );
};

int main ()
{
B b; // OK
C c; // OK
}

Note the semicolon at the end of class A and the int main instead of void main.


Such details matter.


Otherwise you can send people who want to help you, on long wild goose chases. And you don't want that, do you? So, make sure the code you post has been accepted by a compiler, except possibly for the troublesome parts that you want to show do not compile.



The trick is to find common parts of B and C, and put them to base class. The stuff that is different should go to constructor parameter of the derived class:


class A { 
virtual std::string get() const=0;
virtual void set(std::string s)=0;
};
class B : public A { B(int a) : a(a) { } int a; };
class C : public A { C(float b) : b(b) { } float b; }

To implement the functions, you'll need the following:


void B::set(std::string s) {
stringstream ss(s);
ss >> a;
}
void C::set(std::string s) {
stringstream ss(s);
ss >> b;
}

The functions look the same, but are actually calling different operator>>.


Related Posts:

0 commentaires:

Enregistrer un commentaire