10

In my application, I'm dealing with a larger-size classes (over 50 methods) each of which is reasonably complex. I'm not worried about the complexity as they are still straight forward in terms of isolating pieces of functionality into smaller methods and then calling them. This is how the number of methods becomes large (a lot of these methods are private - specifically isolating pieces of functionality).

However when I get to the implementation stage, I find that I loose track of which methods have been implemented and which ones have not been. Then at linking stage I receive errors for the unimplemented methods. This would be fine, but there are a lot of interdependencies between classes and in order to link the app I would need to get EVERYTHING ready. Yet I would prefer to get one class our of the way before moving to the next one.

For reasons beyond my control, I cannot use an IDE - only a plain text editor and g++ compiler. Is there any way to find unimplemented methods in one class without doing a full linking? Right now I literally do text search on method signatures in the implementation cpp file for each of the methods, but this is very time consuming.

4

8 に答える 8

3

実装するすべてのメソッドにスタブを追加して、次のことを行うことができます。

void SomeClass::someMethod() {
    #error Not implemented
}

gcc を使用すると、ファイル、行番号、およびそれぞれのエラー メッセージが出力されます。したがって、問題のモジュールをコンパイルし、リンカーを実行することなく、「実装されていません」を grep することができます。

ただし、これらのスタブを実装ファイルに追加する必要がありますが、これは最初に回避しようとしていたものの一部である可能性があります。

于 2013-01-14T11:50:08.277 に答える
0

それが単体テストとテスト カバレッジ ツールの目的です。すべての機能に対して最小限のテストを事前に記述します。欠落している関数のテストはリンクされません。テスト カバレッジ レポートは、すべての関数がアクセスされたかどうかを示します。

もちろん、それはある程度の助けになるだけで、100% 絶対確実というわけではありません。ただし、あなたの開発方法論は私には少し危険に思えます:クラスを1つずつ分離して開発することは実際には機能しません:互いに依存する(そして覚えておいてください:依存関係を減らす!)クラスはある程度ロックステップで開発する必要があります。あるクラスの完全な実装を大量生産して、振り返ることなく次のクラスに移ることはできません。

于 2013-01-14T12:41:47.010 に答える
0

過去に、各クラスの実行可能ファイルを作成しました。

#include "klass.h"
int main() {
    Klass object;
    return 0;        
}

これにより、ビルド時間が短縮され、一度に 1 つのクラスに集中できるようになり、フィードバック ループが高速化されます。

簡単に自動化できます。

私は本当にそのクラスのサイズを縮小することを検討します!

編集

ハードルがある場合は、力ずくで行くことができます。

#include "klass.h"

Klass createObject() {
    return *reinterpret_cast<Klass>(0);
}    

int main() {
    Klass object = createObject();
    return 0;        
}
于 2013-01-14T12:28:10.810 に答える
0

実際にリンクを試みずにこれを行う簡単な方法はわかりませんが、「ClassInQuestion:: への未定義の参照」のリンカー出力を grep することができます。これにより、指定されたクラスのメソッドのこのエラーに関連する行のみが表示されます。 .

これにより、少なくともリンク プロセス全体からすべてのエラー メッセージをふるいにかけることを回避できますが、完全なリンクを実行する必要がなくなるわけではありません。

于 2013-01-14T11:41:20.973 に答える
0

C ++ 11のdeleteキーワードがそのトリックを行います

struct S{
  void f()=delete; //unimplemented
};

C++11 が利用できない場合は、回避策としてプライベートを使用できます

struct S{
  private: //unimplemented
  void f();
};

この 2 つの方法を使用すると、テスト コードを .cpp ファイルに記述できます。

//test_S.cpp
#include "S.hpp"
namespace{
  void test(){
    S* s;
    s->f(); //will trigger a compilation error
  }
}

テスト コードは決して実行されないことに注意してください。名前空間{}は、このコードが現在のコンパイル ユニット (つまり、test_S.cpp) の外部で使用されることは決してないため、コンパイル チェックの直後に削除されることをリンカーに伝えます。

このコードは実行されないため、テスト関数で実際の S オブジェクトを実際に作成する必要はありません。S オブジェクトに呼び出し可能な f() 関数があるかどうかをテストするために、コンパイラを騙したいだけです。

于 2014-12-16T11:39:44.197 に答える
0

次のように、カスタム例外を作成してスローできます。

  • 実装されていない関数を呼び出すと、予期しない状態のままになる代わりに、アプリケーションが終了します
  • 必要な機能が実装されていなくても、コードをコンパイルできます
  • 実装されていない関数は、コンパイラの警告を確認するか (厄介なトリックを使用して)、プロジェクト ディレクトリを検索することで簡単に見つけることができます。
  • 必要に応じてリリース ビルドから例外を削除できます。これにより、例外をスローしようとする関数がある場合にビルド エラーが発生します。
#if defined(DEBUG)

#if defined(__GNUC__)
#define DEPRECATED(f, m) f __attribute__((deprecated(m)))
#elif defined(_MSC_VER)
#define DEPRECATED(f, m) __declspec(deprecated(m)) f
#else
#define DEPRECATED(f, m) f
#endif

class not_implemented : public std::logic_error {
public:
    DEPRECATED(not_implemented(), "\nUnimplemented function") : logic_error("Not implemented.") { }
}

#endif // DEBUG

実装されていない関数は次のようになります。

void doComplexTask() {
    throw not_implemented();
}

これらの実装されていない関数は、複数の方法で探すことができます。GCC では、デバッグ ビルドの出力は次のようになります。

main.cpp: In function ‘void doComplexTask()’:
main.cpp:21:27: warning: ‘not_implemented::not_implemented()’ is deprecated: 
Unimplemented function [-Wdeprecated-declarations]
     throw not_implemented();
                           ^
main.cpp:15:16: note: declared here
     DEPRECATED(not_implemented(), "\nUnimplemented function") : logic_error("Not implemented.") { }
                ^~~~~~~~~~~~~~~
main.cpp:6:26: note: in definition of macro ‘DEPRECATED’
 #define DEPRECATED(f, m) f __attribute__((deprecated(m)))

リリース ビルド:

main.cpp: In function ‘void doComplexTask()’:
main.cpp:21:11: error: ‘not_implemented’ was not declared in this scope
     throw not_implemented;
           ^~~~~~~~~~~~~~~

次の方法で例外を検索できますgrep

$ grep -Enr "\bthrow\s+not_implemented\b"
main.cpp:21:    throw not_implemented();

を使用する利点はgrepgrepビルド構成を気にせず、関係なくすべてを見つけることです。非推奨の修飾子を削除して、コンパイラの出力をクリーンアップすることもできます。上記のハックは、無関係なノイズを大量に生成します。優先順位によっては、これが不利になる場合があります (たとえば、現在 Linux 固有の機能を実装している場合、Windows 固有の機能を気にしない、またはその逆)。

IDE を使用している場合、ほとんどの場合、プロジェクト全体を検索できます。シンボルを右クリックして、それが使用されているすべての場所を検索できるものもあります。(しかし、あなたはそれを使用できないと言ったので、あなたの場合grepはあなたの友達です。)

于 2018-06-05T04:26:46.793 に答える
0

メソッドの実装のヘッダー ファイルを分析する小さなスクリプトを作成し (正規表現を使用すると、これは非常に簡単になります)、実装ファイルをスキャンして同じメソッドの実装を見つけることができます。

たとえば、Ruby の場合 (C++ コンパイル ユニットの場合):

className = "" # Either hard-code or Regex /class \w+/
allMethods = []

# Scan header file for methods
File.open(<headerFile>, "r") do |file|
    allLines = file.map { |line| line }
    allLines.each do |line|
        if (line =~ /(\);)$/) # Finds lines ending in ");" (end of method decl.)
            allMethods << line.strip!
        end
    end
end

implementedMethods = []
yetToImplement = []

# Scan implementation file for same methods
File.open(<implementationFile>, "r") do |file|
    contents = file.read
    allMethods.each do |method|
        if (contents.include?(method)) # Or (className + "::" + method)
            implementedMethods << method
        else
            yetToImplement << method
        end
    end
end

# Print the results (may need to scroll the code window)
print "Yet to implement:\n"
yetToImplement.each do |method|
    print (method + "\n")
end

print "\nAlready implemented:\n"
implementedMethods.each do |method
    print (method + "\n")
end

これをビルド プロセスに自動化する方法については、他の人が教えてくれるでしょうが、これは、まだ実装されていないメソッドをすばやく確認する 1 つの方法です。

于 2013-01-14T23:08:06.307 に答える
-1

これを行う簡単な方法がわかりません。実装されていないクラスがいくつかあると、複数メンバーのチームで追跡することが困難になる状況が簡単に発生します。

個人的には、自分が書いた各クラスを単体テストしたいと考えており、テスト駆動開発をお勧めします。ただし、これにはステータスを確認するたびにコードをリンクする必要があります。TDD を使用するツールについては、こちらのリンクを参照してください。

もう 1 つのオプションは、ソースを解析して実装する機能をチェックできるコードを書くことです。GCC_XML は良い出発点です。

于 2013-01-14T10:59:44.080 に答える