Thread: c++ class scope issues

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    23

    c++ class scope issues

    This is my first time here, so I hope I meet the expectations for the forums.

    I am trying to make a futures contracts trading program interfacing with interactive brokers' twsapi. I found some c code which seems to make the interface simple, but I'm getting compiler errors that I have never seen before.

    I have a market class and a cell class. the market class contains a 2d array of cells in addition to other information like the current trading price etc...

    Here is how my files depend on eachother right now (arrows point to included files):

    Code:
    main.cpp
       |
      \/
    TWSAPI.h <--- TWSAPI.c
       |
      \/
    market.h <--- market.cpp
       |
      \/
    cell.h <--- cell.cpp
    the TWSAPI essentially gives me a void event_update(data, data, data) function to override, which is called whenever data is received from the server. I need to take that data and store it in my market class. The problem is that I can't access my market object from within the function. Unless it is passed as a parameter, I can't think of how to do this, and I haven't been successful with passing it in as a parameter because I'm trying to pass a class through a c function. I could sure use some help here. I feel like there should be a way to declare my market as a global or change the twsapi.c into a cpp file (I'm not sure if this is as easy as I think it should be). I signed a NDA and some of the code is not allowed to become public so if you need to see code, let me know and I'll give everything I can.

    Thanks for your time.

  2. #2
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    So you're trying to modify a c++ object from a C function?

    Making it into a cpp file would probably be first option I'd consider.

    What I'd try is this:
    In TWSAPI.h declare a market data struct that holds the relevant data of the market class. When the file is included all the function prototypes are in an extern "C" block.
    Your market class needs to hold a market data struct. I think this can simply be a data member. Make event_update take a pointer to the market data struct.

    I think that would work, but I'm not 100% sure. It wouldn't surprise me if that worked on some compilers but not on others.

    Worst comes to worst, you can make the market data a big char array, and rely on accessors methods/functions to get the data. That's bound to work, because the sizes of char arrays are well defined as being the same in c and c++.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  3. #3
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    C++ way
    I would first try copying the twsapi.c file to a twsapi.cpp file, and then try compiling it. Depending on how it was written it may be fairly easy to convert. There are a few differences between the languages, but if you know both languages, translating it may be easy. If it's a short file, it may even compile as is. If this isn't possible then see below.

    C way
    If the market class only contains data (no member functions), then you should be able to pass a pointer the market class to the function:
    Code:
    void event_update(marketClass *market)
    If the market class also contains member functions, then I'm not sure it's possible. You may have to make a struct within the market class which contains all the data for the market class, then pass that to the C function.
    Last edited by swoopy; 10-16-2007 at 09:27 PM.

  4. #4
    Registered User
    Join Date
    Oct 2007
    Posts
    23
    I've received good suggestions so far so thank you. I think I shall make this forum my home.

    I had tried changing the .c extension to .cpp earlier this evening but I think it caused some problems. I will mess with it some more tomorrow. Passing a struct does look like a good idea. I might even consider changing my classes to structs so that I can just pass everything in (even though I would lose the encapsulation).

    On a different note, would it be wise or even possible to pass a void pointer to the market object into the event_update function and access the data by incrementing the pointer an appropriate amount? member functions or not, shouldn't I be able to access the heap?

  5. #5
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by avatarofhope2 View Post
    On a different note, would it be wise or even possible to pass a void pointer to the market object into the event_update function and access the data by incrementing the pointer an appropriate amount? member functions or not, shouldn't I be able to access the heap?
    Not portably. Classes may be matted, so that members are aligned to 2-byte or 4-byte units. So this:
    Code:
    struct example{
    int a;
    char b;
    int c;
    };
    May be represented by the following memory map:
    Code:
    1    a_1
    2    a_2
    3    a_3
    4    a_4
    5    b
    6    --
    7    --
    8    --
    9    c_1
    10   c_2
    11   c_3
    12   c_4
    Also, virtual functions may add a pointer to either the beginning or end of the class.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  6. #6
    Registered User
    Join Date
    Oct 2007
    Posts
    23
    I've attached the API because I would like to try to pass a class into the functions before I redesign my classes, but the code will not compile as c++ code. I discourage you from looking at the whole cpp file unless you are extremely generous and have plenty of time. Instead I ask about the first error returned when I compile twsapi.c as twsapi.cpp.

    Attachment 7572
    Attachment 7571

    Code:
    twsapi.cpp(159) : error C2440: 'initializing' : cannot convert
    from 'tr_contract_details::contract_details_summary *__w64 '
    to 'init_contract_details::contract_details_summary *'
    
    Types pointed to are unrelated; conversion requires reinterpret_cast, 
    C-style cast or function-style cast
    here is the code at the line under question:
    Code:
    struct contract_details_summary *ds = &cd->d_summary;
    I'm not sure whats going on here. Any ideas?

  7. #7
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    That could just be that if you are compiling as *.cpp then you do not need extern "C" in the header file.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    To me, it looks like there is two definitions of struct contract_details_summary, one in tr_contract_details
    and one in
    init_contract_details

    The compiler tries to translate one to the other, when I think you should use one and the same for both.

    I could have it wrong...

    Edit: Looking at the code, it seems like your problem is not what I described above. One possible solution is to move the struct contract_details_summary out of the struct tr_contract_details - I beleive that will solve the problem with the least amount of changes.

    --
    Mats
    Last edited by matsp; 10-18-2007 at 02:19 AM.
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Oct 2007
    Posts
    23
    so in C++, designers removed the functionality to define a struct within the definition of another struct? I pulled the struct out like you suggested and I received much fewer compiler errors (5 total). one is:

    Code:
    twsapi.cpp(813) : error C2440: 'initializing' : cannot convert from 'void *' to 'tws_instance_t *'
    1>        Conversion from 'void*' to pointer to non-'void' requires an explicit cast
    i added the explicit cast (tws_instance_t *), but I'm not confident that this is a good thing to do. Why would this cast be necessary in C++ and not in C?

    Removing the extern "C" (and its # directives) didn't seem to do anything. I've never had to use extern before and I'm not clear on what "C" actually is. It seems like it is saying that a literal is defined in another file. What is the point of that?

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by avatarofhope2 View Post
    so in C++, designers removed the functionality to define a struct within the definition of another struct? I pulled the struct out like you suggested and I received much fewer compiler errors (5 total). one is:

    Code:
    twsapi.cpp(813) : error C2440: 'initializing' : cannot convert from 'void *' to 'tws_instance_t *'
    1>        Conversion from 'void*' to pointer to non-'void' requires an explicit cast
    i added the explicit cast (tws_instance_t *), but I'm not confident that this is a good thing to do. Why would this cast be necessary in C++ and not in C?

    Removing the extern "C" (and its # directives) didn't seem to do anything. I've never had to use extern before and I'm not clear on what "C" actually is. It seems like it is saying that a literal is defined in another file. What is the point of that?
    To your first part: Yes, there are subtle differences between C and C++ when it comes to structure scope and such things. Since in C++ a struct and a class is esssentially the same thing, your struct definition inside a class/struct becaomes a "local" definition. If you really want the struct to be inside your other struct, you could prefix it with "outer_struct_name::inner_struct" [can't be bothered to look up the exact names in your case].

    Second piece: void * is compatible with all pointers in C, but C++ doesn't allow the assignment of struct type pointers [again, because it's essentially a class] directly from a void *, because you may in this case bypass the constructor - you should use new to allocate new data and objects according to the design of the language. If it's a plain data structure, it is of course fine to just cast it.

    Third piece: the construction extern "C" tells the compiler that "the following piece is not C++ standard, but C". It has little to do with "extern" in the sense of "this function is somewhere else and not in this object file".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User
    Join Date
    Oct 2007
    Posts
    23
    I think I have sufficiently resolved the previous problems, but I have a new compiler error that I have never seen before. If anyone here has seen something like this error and has any insight into its cause, I would appreciate advice.

    Code:
    twsapi.obj : error LNK2019: unresolved external symbol 
    "public: __thiscall market::market(class market const &)" 
    (??0market@@QAE@ABV0@@Z) referenced in function 
    "void __cdecl receive_tick_price(struct tws_instance *)" 
    (?receive_tick_price@@YAXPAUtws_instance@@@Z)
    it looks like it is trying to make a copy of a market object in receive_tick_price().
    Last edited by avatarofhope2; 10-23-2007 at 05:23 PM.

  12. #12
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    It looks like you declared a copy constructor for market, but the linker could not find the implementation.

    This can happen for several reasons. Perhaps you forgot to implement that function. Maybe you implemented it in a source file but forgot to add that source file to your project/makefile/command line. Maybe you implemented that function but forgot to add the market:: to the front so the compiler knew it was a member function of the market class. Maybe you meant to disable copying of market but made the copy constructor public instead of private so that receive_tick_price has access to the declaration.

    If you can't find the problem, show the declaration of the copy constructor inside market and the code that implements the copy constructor function as well.

  13. #13
    Registered User
    Join Date
    Oct 2007
    Posts
    23
    Quote Originally Posted by Daved View Post
    It looks like you declared a copy constructor for market, but the linker could not find the implementation.
    hurray thank you. it successfully compiled. I had a copy constructor prototype but no definition because I thought I would get the default copy constructor. apparently I was misinformed

  14. #14
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    If you want the default copy constructor (which you often do), then just remove the prototype. Some people recommend leaving a comment in its place that states that the default copy constructor is appropriate.

    Same goes for the copy assignment operator and the destructor.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. help on class coupling
    By andrea72 in forum C++ Programming
    Replies: 4
    Last Post: 04-17-2011, 10:16 AM
  2. Default class template problem
    By Elysia in forum C++ Programming
    Replies: 5
    Last Post: 07-11-2008, 08:44 AM
  3. class composition constructor question...
    By andrea72 in forum C++ Programming
    Replies: 3
    Last Post: 04-03-2008, 05:11 PM
  4. Creating a database
    By Shamino in forum Game Programming
    Replies: 19
    Last Post: 06-10-2007, 01:09 PM
  5. gcc problem
    By bjdea1 in forum Linux Programming
    Replies: 13
    Last Post: 04-29-2002, 06:51 PM