C++에는 Java 및 C#의 interface
기능이 없으므로 C++ 클래스에서 인터페이스를 시뮬레이트하는 데 가장 적합한 방법은 무엇입니까? 내 추측은 추상 클래스의 다중 상속 것입니다.메모리 오버 헤드/성능에 어떤 영향이 있습니까? SerializableInterface
과 같은 시뮬레이트 된 인터페이스에 대한 명명 규칙이 있습니까?C++에서 인터페이스를 시뮬레이트하려면 어떻게해야합니까?
답변
C++에는 C# 및 Java와 달리 다중 상속이 있으므로 일련의 추상 클래스를 만들 수 있습니다.
관습에 관해서는 당신에게 달려 있습니다. 그러나, 나는 I.
class IStringNotifier
{
public:
virtual void sendMessage(std::string &strMessage) = 0;
virtual ~IStringNotifier() { }
};
성능은 C# 및 자바의 비교의 관점에서 걱정할 필요 없다와 클래스 이름 앞에 것을 좋아합니다. 기본적으로 함수에 대한 조회 테이블이나 가상 메소드가있는 상속과 같은 vtable이있는 오버 헤드가 있습니다.
추상 클래스 만들기 추상 클래스에 대한 포인터를 사용하여 객체를 삭제하려는 경우 가상 소멸자. –
@ 황홍 : 동의가 명시 적으로 추가되었습니다. –
@Michael Aaron Safyan : downvote에 감사드립니다. 코딩 스타일에 대한 선호가 아닌 답을 통해 질문을 판단하면 좋을지도 모릅니다. –
C++의 인터페이스는 순수 가상 함수 만 갖는 클래스입니다. 예 : :
class ISerializable
{
public:
virtual ~ISerializable() = 0;
virtual void serialize(stream& target) = 0;
};
이것은 시뮬레이션 된 인터페이스가 아니며 Java의 인터페이스와 유사하지만 단점을 가지고 있지 않습니다.
예. 당신은 부정적인 결과없이 방법과 구성원을 추가 할 수 있습니다 :
이름 지정 규칙에class ISerializable
{
public:
virtual ~ISerializable() = 0;
virtual void serialize(stream& target) = 0;
protected:
void serialize_atomic(int i, stream& t);
bool serialized;
};
...는 C++ 언어로 정의 된 실제 명명 규칙이 없습니다. 그래서 당신의 환경에서 하나를 선택하십시오.
오버 헤드는 1 개의 정적 테이블이며 아직 가상 함수가없는 파생 클래스에서 정적 테이블에 대한 포인터입니다.
나는 가상 생성자를 가질 수 있다고 생각하지 않는다. 가상 소멸자를 가질 수 있습니다. – jkeys
@hooked, 타이핑 오류가 수정되었습니다. – Christopher
소멸자가 순수 가상이되는 이유는 없습니다. 그냥 평범한 가상으로 충분할 것입니다. 또한 dtor을 선언하는 것은 이 아니므로 정의해야합니다. 순수 가상 dtor 의 경우에는 다음과 같이 클래스 정의 외부에서 정의해야합니다. ISerializable :: ~ ISerializable() {} C++ 문법이 순수 가상 지정자 과 클래스 멤버 함수를 모두 허용하지 않기 때문에 정의. –
가상 상속을 사용하지 않는 경우 오버 헤드는 최소한 하나 이상의 가상 함수가있는 일반적인 상속보다 나쁘지 않아야합니다. 상속받은 각 추상 클래스는 각 객체에 대한 포인터를 추가합니다. 당신은 빈 기본 클래스 최적화 뭔가를 할 경우
그러나, 당신은을 최소화 할 수 있습니다 :
struct A { void func1() = 0; }; struct B: A { void func2() = 0; }; struct C: B { int i; };
C의 크기를 두 단어 일 것이다.
"메모리 오버 헤드/성능에 어떤 영향이 있습니까?"
일반적으로 가상 전화를 사용하는 경우를 제외하고는 성능 측면에서 표준에 의해 보장되는 것은 아무것도 없습니다.
메모리 오버 헤드에서 "빈 기본 클래스"최적화는 컴파일러가 데이터 멤버가없는 기본 클래스를 추가해도 개체 크기가 증가하지 않도록 레이아웃 구조를 명시 적으로 허용합니다. 나는 이것을하지 않는 컴파일러를 다루지는 않을 것 같지만 잘못 될 수 있습니다.
클래스에 첫 번째 가상 멤버 함수를 추가하면 일반적으로 가상 멤버 함수가없는 경우와 비교하여 포인터 크기만큼 개체가 증가합니다. 가상 멤버 함수를 추가하면 추가적인 차이가 없습니다. 가상 기본 클래스를 추가하면 더 많은 차이를 만들 수 있지만, 사용자가 말하는 것에 대해서는 필요하지 않습니다.
가상 멤버 함수를 사용하여 여러 기본 클래스를 추가하는 것은 실제로 일반적인 구현에서 개체에 여러 vtable 포인터가 필요하기 때문에 실제로는 기본 클래스 최적화를 한 번만 수행한다는 것을 의미합니다. 따라서 각 클래스에 여러 인터페이스가 필요한 경우 개체 크기에 추가 할 수 있습니다.
성능면에서 가상 함수 호출은 비 가상 함수 호출보다 약간 더 많은 오버 헤드가 있으며 더 중요한 것은 일반적으로 (항상?) 인라인되지 않는다고 가정 할 수 있습니다. 빈 기본 클래스를 추가하는 것은 일반적으로 빈 기본 생성자 및 소멸자가 파생 클래스 생성자/소멸자 코드로 인라인 될 수 있으므로 생성 또는 삭제에 코드를 추가하지 않습니다.
명시 적 인터페이스를 원한다면 가상 기능을 피하기 위해 사용할 수있는 트릭이 있지만 동적 다형성은 필요하지 않습니다. 그러나 자바를 에뮬레이션하려는 경우 그럴 수 없다고 가정합니다.
는예제 코드 :
#include <iostream>
// A is an interface
struct A {
virtual ~A() {};
virtual int a(int) = 0;
};
// B is an interface
struct B {
virtual ~B() {};
virtual int b(int) = 0;
};
// C has no interfaces, but does have a virtual member function
struct C {
~C() {}
int c;
virtual int getc(int) { return c; }
};
// D has one interface
struct D : public A {
~D() {}
int d;
int a(int) { return d; }
};
// E has two interfaces
struct E : public A, public B{
~E() {}
int e;
int a(int) { return e; }
int b(int) { return e; }
};
int main() {
E e; D d; C c;
std::cout << "A : " << sizeof(A) << "\n";
std::cout << "B : " << sizeof(B) << "\n";
std::cout << "C : " << sizeof(C) << "\n";
std::cout << "D : " << sizeof(D) << "\n";
std::cout << "E : " << sizeof(E) << "\n";
}
출력 (32 비트 플랫폼에서 GCC는) : 아무것도없는
있다A : 4
B : 4
C : 8
D : 8
E : 12
정말 그 C++ 아니므로 무엇을 '시뮬레이션'을 할 필요가 없다는 것을 자바 인터페이스로 할 수 있습니다.
Java는 뷰의 C++ 포인터에서 interface
과 class
사이에 "인공적인"구별을합니다. interface
은 모두 단지 class
이며 모든 메소드가 추상적이고 데이터 멤버를 포함 할 수 없습니다.
Java는 제한되지 않은 다중 상속을 허용하지 않기 때문에이 제한을 적용하지만 class
에서 implement
개의 여러 인터페이스를 허용합니다.
C++에서, class
은 class
이고 interface
은 class
입니다. extends
은 공개 상속으로 이루어지며 implements
은 공개 상속으로도 달성됩니다.
여러 인터페이스가 아닌 클래스에서 상속하면 추가적인 문제가 발생할 수 있지만 상황에 따라 유용 할 수 있습니다. 하나의 비 인터페이스 클래스와 완전히 추상적 인 클래스에서 상속하는 클래스로만 자신을 제한하면 Java (다른 C++/Java 차이점 제외)보다 다른 어려움이 발생하지 않습니다.
메모리 및 오버 헤드 비용 측면에서 Java 스타일 클래스 계층 구조를 다시 만드는 경우 어쨌든 클래스에 가상 함수 비용을 지불했을 것입니다. 어쨌든 서로 다른 런타임 환경을 사용한다고 가정하면 서로 다른 상속 모델의 비용면에서 두 가지 사이의 오버 헤드에 근본적인 차이는 없을 것입니다.
MSVC 2008의 키워드는 __interface입니다.
A Visual C++ interface can be defined as follows:
- Can inherit from zero or more base
interfaces.
- Cannot inherit from a base class.
- Can only contain public, pure virtual
methods.
- Cannot contain constructors,
destructors, or operators.
- Cannot contain static methods.
- Cannot contain data members;
properties are allowed.
이 기능은 Microsoft 특정 기능입니다. 주의 : __interface에는 인터페이스 포인터로 개체를 삭제할 때 필요한 가상 소멸자가 없습니다.
이것이 C++을 수행하는 COM/DCOM의 방식이라고 생각합니다. –
왜 그렇게 생각하니? –
COM 인터페이스로 작업 할 때 사용하는 유일한 장소이기 때문에 ;-) 사용했습니다. –
C++에서 우리는 평범한 비헤이비어가 아닌 Java & 인터페이스보다 더 나아갈 수 있습니다. NVI 패턴을 사용하여 명시 적 계약 (계약 : 계약)을 추가 할 수 있습니다.
struct Contract1 : noncopyable
{
virtual ~Contract1();
Res f(Param p) {
assert(f_precondition(p) && "C1::f precondition failed");
const Res r = do_f(p);
assert(f_postcondition(p,r) && "C1::f postcondition failed");
return r;
}
private:
virtual Res do_f(Param p) = 0;
};
struct Concrete : virtual Contract1, virtual Contract2
{
...
};
요청하는 방식대로 인터페이스를 구현하는 좋은 방법은 없습니다. 완전히 추상적 인 ISerializable 기본 클래스와 같은 접근법의 문제점은 C++이 다중 상속을 구현하는 방식에 있습니다. 다음 고려 :
class Base
{
};
class ISerializable
{
public:
virtual string toSerial() = 0;
virtual void fromSerial(const string& s) = 0;
};
class Subclass : public Base, public ISerializable
{
};
void someFunc(fstream& out, const ISerializable& o)
{
out << o.toSerial();
}
가 분명히 의도는 함수 toSerial()는 기본 클래스에서 상속을 포함한 서브 클래스의 모든 멤버를 직렬화하기위한 것입니다. 문제는 ISerializable에서 Base 로의 경로가 없다는 것입니다.
void fn(Base& b)
{
cout << (void*)&b << endl;
}
void fn(ISerializable& i)
{
cout << (void*)&i << endl;
}
void someFunc(Subclass& s)
{
fn(s);
fn(s);
}
첫 번째 호출에 의한 값의 출력은 두 번째 호출에 의한 값의 출력과 동일하지 않습니다 : 다음 실행할 경우 그래픽으로 볼 수 있습니다. 두 경우 모두에서 s에 대한 참조가 전달 되더라도 컴파일러는 전달 된 주소를 적절한 기본 클래스 유형과 일치하도록 조정합니다.
- 1. JavaScript로 매크로를 시뮬레이트하려면 어떻게해야합니까?
- 2. 세션 손실 상태를 시뮬레이트하려면 어떻게해야합니까?
- 3. jQuery를 사용하여 스크롤 막대 클릭을 시뮬레이트하려면 어떻게해야합니까?
- 4. C에서 사용자 지정 DirectShow 필터 인터페이스를 정렬합니다. #
- 5. Windows Phone 7 에뮬레이터에서 멀티 터치를 시뮬레이트하려면 어떻게해야합니까?
- 6. Windows에서 포트 80을 통한 RTMP 차단을 시뮬레이트하려면 어떻게해야합니까?
- 7. Qt에서 사용자 상호 작용 (키 누름 이벤트)을 시뮬레이트하려면 어떻게해야합니까?
- 8. jScrollPane 세로 탭 - 링크/탭의 클릭을 시뮬레이트하려면 어떻게해야합니까?
- 9. JS를 사용하여 Chrome에서 링크를 클릭 한 이벤트를 시뮬레이트하려면 어떻게해야합니까?
- 10. 현재 포커스가있는 모든 창에서 키 누르기를 시뮬레이트하려면 어떻게해야합니까?
- 11. jquery 유효성 검사 플러그인을 사용하여 유효성 그룹을 시뮬레이트하려면 어떻게해야합니까?
- 12. WCF 서비스에서 인터페이스를 반환하려면 어떻게해야합니까?
- 13. 다른 파일에서 인터페이스를 구현하려면 어떻게해야합니까?
- 14. 이 일반 인터페이스를 전송하려면 어떻게해야합니까?
- 15. C에서 SMTP를 인증하려면 어떻게해야합니까?
- 16. C에서 라이브러리를 추가하려면 어떻게해야합니까?
- 17. C에서 콜백 함수를 구현하려면 어떻게해야합니까?
- 18. C에서 메타 클래스를 구현하려면 어떻게해야합니까?
- 19. C에서 tcsetpgrp()를 사용하려면 어떻게해야합니까?
- 20. Objective C에서 javaScript를 호출하려면 어떻게해야합니까?
- 21. LPVOID 버퍼에 JNA 인터페이스를 구현하려면 어떻게해야합니까?
- 22. C#에서 BaaN 인터페이스를 만들려면 어떻게해야합니까?
- 23. BB Messenger와 같은 인터페이스를 구현하려면 어떻게해야합니까?
- 24. 데이터 형식이 IComparable 인터페이스를 구현하는지 확인하려면 어떻게해야합니까?
- 25. JiBX : 코드에서 인터페이스를 계속 사용하려면 어떻게해야합니까?
- 26. 주어진 유형이 어떤 인터페이스를 구현하는 경우 어떻게해야합니까?
- 27. 마커 인터페이스를 등록하여 Plones의 ZMI에 표시되도록하려면 어떻게해야합니까?
- 28. 인터페이스를 차단하지 않고 NSTableView에 대한 데이터를로드하려면 어떻게해야합니까?
- 29. iBook 스타일의 사용자 인터페이스를 만들려면 어떻게해야합니까?
- 30. 직접 클래스를 인스턴스화하거나 C에서 제어 인터페이스를 통해 인스턴스화 사이의 차이 #
인터페이스가 부족합니다. 그것은 부정적인 표현처럼 보입니다. C++은 인터페이스가 부족하지 않습니다 (클래스는 인터페이스입니다). 키워드 인터페이스가 부족합니다. 왜곡되지 않았기 때문입니다. –
Interface 키워드는 코드 나 데이터가 포함되지 않도록 보장되어 다른 인터페이스와 쉽게 상호 작용할 수 있습니다. C++에서 이러한 보증을 할 수있는 방법이 없습니다. 충돌이 발생하지 않기를 바랄뿐입니다. Java와 C#이 코드 가독성, 상호 운용성 및 이해 가능성을 위해 많은 것들이 C++로 작업하는 동안 사람들이 겪었던 문제에 대한 응답으로 파악되었습니다. –
[C++에서 인터페이스를 어떻게 선언합니까?] (http://stackoverflow.com/questions/318064/how-do-you-declare-an-interface-in-c) –