Y
yccheok
I try to write a c implementation of java abstract class which serve
the same purpose. however, I feel that there might be some potential
holes in the future especially when I plan to scale up this software
piece.
Please consider the following Java code.
=== Start Java ===
interface animal {
public void speak();
}
class dog implements animal {
long dummy; /* please not that cat is having short type */
public void speak() {
System.out.println("I am a happy dog. Wow! Wow!");
}
}
class cat implements animal {
short dummy; /* please not that dog is having long type */
public void speak() {
System.out.println("I am a sad cat. Meow! Meow!");
}
}
public class driver {
public static void main(String[] args) {
animal animal1 = new dog();
animal animal2 = new cat();
animal1.speak();
animal2.speak();
}
}
=== End Java ===
=== Start C ===
#include <stdio.h>
typedef struct tagAnimal{
void (*speak)(void) __attribute__((packed));
void (*delete)(struct tagAnimal *) __attribute__((packed));
} animal;
typedef struct {
void (*speak)(void) __attribute__((packed));
void (*delete)(animal *) __attribute__((packed));
/* Cannt just place dummy before speak function pointer.
* This will cause problem while trying to cast dog
* from animal
*/
long dummy __attribute__((packed));
} dog;
typedef struct {
void (*speak)(void) __attribute__((packed));
void (*delete)(animal *) __attribute__((packed));
/* Cannt just place dummy before speak function pointer.
* This will cause problem while trying to cast cat
* from animal
*/
short dummy __attribute__((packed));
} cat;
animal* createDog(void);
animal* createCat(void);
void deleteDog(animal *myAnimal);
void deleteCat(animal *myAnimal);
void dogSpeak(void);
void catSpeak(void);
animal *createDog() {
dog *myDog = (dog *)calloc(1, sizeof(dog));
myDog->speak = dogSpeak;
myDog->delete = deleteDog;
return((animal *)myDog);
}
void deleteDog(animal *myAnimal) {
free((void*)myAnimal);
}
animal *createCat() {
cat *myCat = (cat *)calloc(1, sizeof(cat));
myCat->speak = catSpeak;
myCat->delete = deleteCat;
return((animal *)myCat);
}
void deleteCat(animal *myAnimal) {
free((void*)myAnimal);
}
void dogSpeak() {
printf("I am a happy dog. Wow! Wow!\n");
}
void catSpeak() {
printf("I am a sad cat. Meow! Meow!\n");
}
int main() {
animal* animal1 = createDog();
animal* animal2 = createCat();
animal1->speak();
animal2->speak();
animal1->delete(animal1);
animal2->delete(animal2);
}
=== End C ===
It work. But here are some potential problem in the future.
1. The size, sequence of the data members inside the struct, have to be
same across the abstract data type (animal) and the concrete data type
(cat, dog).
Say, the following will cause problem
typedef struct tagAnimal{
void (*speak)(void) __attribute__((packed));
void (*delete)(struct tagAnimal *) __attribute__((packed));
} animal;
typedef struct {
long dummy;
void (*speak)(void) __attribute__((packed));
void (*delete)(animal *) __attribute__((packed));
} dog;
Please note that the dummy member has been moved from the bottom to
top. This will screw up everything while we try to cast from dog to
animal, and access function through animal.
Hence, everytime the programmers try to add a new member elements to
the concrete data type (dog, cat), they have to be **VERY VERY**
caution on the size and the sequence of the members with respect to the
abstract data type.
Proper documentation on the struct may help to reduce this from happen.
But are not gurantee. If there any better way we can prevent this from
happen?
Or should I re-design the whole architecture? If yes, how can I
re-implement the above Java class?
Thank you very much!
-cheok
the same purpose. however, I feel that there might be some potential
holes in the future especially when I plan to scale up this software
piece.
Please consider the following Java code.
=== Start Java ===
interface animal {
public void speak();
}
class dog implements animal {
long dummy; /* please not that cat is having short type */
public void speak() {
System.out.println("I am a happy dog. Wow! Wow!");
}
}
class cat implements animal {
short dummy; /* please not that dog is having long type */
public void speak() {
System.out.println("I am a sad cat. Meow! Meow!");
}
}
public class driver {
public static void main(String[] args) {
animal animal1 = new dog();
animal animal2 = new cat();
animal1.speak();
animal2.speak();
}
}
=== End Java ===
=== Start C ===
#include <stdio.h>
typedef struct tagAnimal{
void (*speak)(void) __attribute__((packed));
void (*delete)(struct tagAnimal *) __attribute__((packed));
} animal;
typedef struct {
void (*speak)(void) __attribute__((packed));
void (*delete)(animal *) __attribute__((packed));
/* Cannt just place dummy before speak function pointer.
* This will cause problem while trying to cast dog
* from animal
*/
long dummy __attribute__((packed));
} dog;
typedef struct {
void (*speak)(void) __attribute__((packed));
void (*delete)(animal *) __attribute__((packed));
/* Cannt just place dummy before speak function pointer.
* This will cause problem while trying to cast cat
* from animal
*/
short dummy __attribute__((packed));
} cat;
animal* createDog(void);
animal* createCat(void);
void deleteDog(animal *myAnimal);
void deleteCat(animal *myAnimal);
void dogSpeak(void);
void catSpeak(void);
animal *createDog() {
dog *myDog = (dog *)calloc(1, sizeof(dog));
myDog->speak = dogSpeak;
myDog->delete = deleteDog;
return((animal *)myDog);
}
void deleteDog(animal *myAnimal) {
free((void*)myAnimal);
}
animal *createCat() {
cat *myCat = (cat *)calloc(1, sizeof(cat));
myCat->speak = catSpeak;
myCat->delete = deleteCat;
return((animal *)myCat);
}
void deleteCat(animal *myAnimal) {
free((void*)myAnimal);
}
void dogSpeak() {
printf("I am a happy dog. Wow! Wow!\n");
}
void catSpeak() {
printf("I am a sad cat. Meow! Meow!\n");
}
int main() {
animal* animal1 = createDog();
animal* animal2 = createCat();
animal1->speak();
animal2->speak();
animal1->delete(animal1);
animal2->delete(animal2);
}
=== End C ===
It work. But here are some potential problem in the future.
1. The size, sequence of the data members inside the struct, have to be
same across the abstract data type (animal) and the concrete data type
(cat, dog).
Say, the following will cause problem
typedef struct tagAnimal{
void (*speak)(void) __attribute__((packed));
void (*delete)(struct tagAnimal *) __attribute__((packed));
} animal;
typedef struct {
long dummy;
void (*speak)(void) __attribute__((packed));
void (*delete)(animal *) __attribute__((packed));
} dog;
Please note that the dummy member has been moved from the bottom to
top. This will screw up everything while we try to cast from dog to
animal, and access function through animal.
Hence, everytime the programmers try to add a new member elements to
the concrete data type (dog, cat), they have to be **VERY VERY**
caution on the size and the sequence of the members with respect to the
abstract data type.
Proper documentation on the struct may help to reduce this from happen.
But are not gurantee. If there any better way we can prevent this from
happen?
Or should I re-design the whole architecture? If yes, how can I
re-implement the above Java class?
Thank you very much!
-cheok