コードに関するいくつかの主にマイナーな問題点。アクティブな名前空間を使用したソリューションの詳細については既に説明しましたが、対処すべきさまざまな小さな問題があります。
typedef struct CABC CABC;
( の代わりにtypedef void CABC;
) 不完全な型を導入して、C コードで型の安全性を確保する方がよいでしょう。FILE *
これにより、たとえば、使用しない C インターフェイス関数にrandom を渡すことvoid
ができなくなります。
不完全型を使用する場合reinterpret_cast<ABC *>(abc)
は、C スタイルのキャストではなく、C ラッパー関数で使用する必要があります。コンパイラは、call_abc_methods()
関数の const-ness に問題があることを示します。引数はそうであってはなりませんconst
(しかし、C スタイルのキャストが問題を隠していました)。
さらに、ABC.hpp
ヘッダーにはよくある (マイナーな) 間違いが示されています。#include <stdio.h>
ヘッダーを安全に使用するために必要のない不要なヘッダー ( ) が含まれています。ABC.cpp
その行は、コードが のサービスを使用する実装ファイル にのみ表示されます<stdio.h>
。ほとんどのヘッダーは#include
、ヘッダーを単独で使用できるようにするために必要な他のヘッダーのみにする必要があります。ランダムな他のヘッダーを含めるべきではありません。
これは完全に機能するプログラムです — これには多くのファイルがあります。3 つのヘッダーがあります。
ABC.hpp
—宣言するclass ABC
。
ABCwrapper.h
— への C インターフェイスを宣言しますclass ABC
。
ABCprogram.h
— 他の機能を宣言するバイリンガル ヘッダー。
1 つの C ファイルがあります。
ABCuser.c
class ABC
—演習全体をやりがいのあるものにするために、C インターフェイスを使用する必要がある C コードがいくつかあるに違いありません。これで終わりです。
3 つの C++ ファイルがあります。
ABC.cpp
— 定義しclass ABC
ます。
ABCwrapper.cpp
— への C インターフェイスを定義しますclass ABC
。
ABCmain.cpp
— バイリンガル システムのメイン プログラムは通常、C++ で記述します。
そして、がありmakefile
ます。
ABC.hpp
#ifndef ABC_HPP_INCLUDED
#define ABC_HPP_INCLUDED
namespace abc_library {
class ABC {
private:
int m_number;
public:
ABC(int p_number);
void doSomething();
virtual ~ABC();
};
} /* namespace abc_library */
#endif /* ABC_HPP_INCLUDED */
ABCwrapper.h
#ifndef ABCWRAPPER_H_INCLUDED
#define ABCWRAPPER_H_INCLUDED
typedef struct CABC CABC; // Pointer to this ncomplete type used in C code
#ifdef __cplusplus
extern "C" {
#endif
CABC *create_abc(int val);
void call_abc_methods(CABC *p_abc);
void destroy_abc(CABC *p_abc);
#ifdef __cplusplus
}
#endif
#endif /* ABCWRAPPER_H_INCLUDED */
ABCprogram.h
#ifndef ABCPROGRAM_H_INCLUDED
#define ABCPROGRAM_H_INCLUDED
#if defined(__cplusplus)
extern "C" {
#endif
extern int c_code_function(int init);
#if defined(__cplusplus)
}
#endif
#endif /* ABCPROGRAM_H_INCLUDED */
ABCuser.c
#include "ABCwrapper.h"
#include "ABCprogram.h"
int c_code_function(int init)
{
CABC *abc = create_abc(init);
call_abc_methods(abc);
destroy_abc(abc);
return 0;
}
ABC.cpp
#include "ABC.hpp"
#include <stdio.h>
using namespace abc_library;
ABC::ABC(int p_number) {
this->m_number = p_number;
}
ABC::~ABC() {
this->m_number = -1;
}
void ABC::doSomething() {
printf("doing something (%d)\n", this->m_number);
}
ABCwrapper.cpp
#include "ABC.hpp"
#include "ABCwrapper.h"
using namespace abc_library;
extern "C" {
CABC *create_abc(int val) {
ABC* abc = new ABC(val);
return reinterpret_cast<CABC*>(abc);
}
void call_abc_methods(CABC *p_abc) {
ABC *abc = reinterpret_cast<ABC *>(p_abc);
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
ABC* abc = reinterpret_cast<ABC *>(p_abc);
delete abc;
}
}
ABCmain.cpp
#include "ABCprogram.h"
int main()
{
return c_code_function(39);
}
メイクファイル
CC = gcc # /usr/bin/gcc
CXX = g++
RM_FR = rm -fr --
WFLAGS = -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition
SFLAGS = -std=c99
OFLAGS = -g -O3
UFLAGS = # Set on make command line only
OXXFLAGS = -g -O3
SXXFLAGS = -std=c++11
WXXFLAGS = -Wall -Wextra
UXXFLAGS = # Set on make command line only
LDFLAGS =
LDLIBS =
CFLAGS = ${OFLAGS} ${SFLAGS} ${WFLAGS} ${UFLAGS}
CXXFLAGS = ${OXXFLAGS} ${SXXFLAGS} ${WXXFLAGS} ${UXXFLAGS}
PROGRAM = abc
FILES.cpp = \
ABC.cpp \
ABCmain.cpp \
ABCwrapper.cpp
FILES.c = \
ABCuser.c
FILES.h = \
ABCprogram.h \
ABCwrapper.h
FILES.o = ${FILES.cpp:.cpp=.o} ${FILES.c:.c=.o}
all: ${PROGRAM}
${PROGRAM}: ${FILES.o}
${CXX} -o $@ ${CXXFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}
clean:
${RM_FR} *.o *.dSYM core a.out
depend:
mkdep ${FILES.cpp} ${FILES.c}
# DO NOT DELETE THIS LINE or the blank line after it -- make depend uses them.
ABC.o: ABC.cpp
ABC.o: ABC.hpp
ABCmain.o: ABCmain.cpp
ABCmain.o: ABCprogram.h
ABCuser.o: ABCprogram.h
ABCuser.o: ABCuser.c
ABCuser.o: ABCwrapper.h
ABCwrapper.o: ABC.hpp
ABCwrapper.o: ABCwrapper.cpp
ABCwrapper.o: ABCwrapper.h