How to Avoid Repeating the Class Name in the Implementation File

Is it possible to avoid repeating the class name in the implementation file?

I'm guessing this is to avoid lots of "unnecessary typing". Sadly there's no way to get rid of the scope (as many other answers have told you) however what I do personally is get the class defined with all my function prototypes in nice rows, then copy/paste into the implementation file then ctrl-c your ClassName:: on the clip board and run up the line with ctrl-v.

c++: Any way to avoid typing the class name before every member function?

No, there is not (unless you define a member function contextually with its declaration, thus when you define your class - that is more or less what happens in Java actually).

In other terms, if you don't want to do this:

// .h
struct S { void f(); };
// .cpp
void S::f() {}

You can still do this:

// .h
struct S { void f() {} };

Anyway it has drawbacks and you could not be prepared to deal with them in any situation.

C++ method implementations: Can I avoid typing the class name each time?

Using C++20 modules, you can implement a class in one file:

module myproject.mymodule;

namespace mynamespace {
export struct my_class {
auto my_method() -> int {
return 8;
}
};
}

Or export a whole namespace fragment:

export namespace mynamespace {
struct my_class {
auto my_method() -> int {
return 8;
}
};

auto also_exported() -> void {
// ...
}
}

Then, instead of including it, you can import that module:

import myproject.mymodule;

auto frob() -> void {
auto my_instance = mynamespace::my_class{};
}

How can I avoid including class implementation files?

Separate compilation in a nutshell

First, let's get some quick examples out there:

struct ClassDeclaration;   // 'class' / 'struct' mean almost the same thing here
struct ClassDefinition {}; // the only difference is default accessibility
// of bases and members

void function_declaration();
void function_definition() {}

extern int global_object_declaration;
int global_object_definition;

template<class T> // cannot replace this 'class' with 'struct'
struct ClassTemplateDeclaration;
template<class T>
struct ClassTemplateDefinition {};

template<class T>
void function_template_declaration();
template<class T>
void function_template_definition() {}

Translation Unit

A translation unit (TU) is a single source file (should be a **.cpp* file) and all the files it includes, and they include, etc. In other words: the result of preprocessing a single file.

Headers

Include guards are a hack to work around lack of a real module system, making headers into a kind of limited module; to this end, including the same header more than once must not have an adverse affect.

Include guards work by making subsequent #includes no-ops, with the definitions available from the first include. Because of their limited nature, macros which control header options should be consistent throughout a project (oddball headers like <assert.h> cause problems) and all #includes of public headers should be outside of any namespace, class, etc., usually at the top of any file.

See my include guard naming advice, including a short program to generate include guards.

Declarations

Classes, functions, objects, and templates may be declared almost anywhere, may be declared any number of times, and must be declared before referring to them in any way. In a few weird cases, you can declare classes as you use them; won't cover that here.

Definitions

Classes may be defined at most once[1] per TU; this typically happens when you include a header for a particular class. Functions and objects must be defined once in exactly one TU; this typically happens when you implement them in a **.cpp* file. However, inline functions, including implicitly inline functions inside class definitions, may be defined in multiple TUs, but the definitions must be identical.

For practical purposes[2], templates (both class templates and function templates) are defined only in headers, and if you want to use a separate file, then use another header[3].

[1] Because of the at-most-once restriction, headers use include guards to prevent multiple inclusion and thus multiple definition errors.

[2] I won't cover the other possibilities here.

[3] Name it blahblah_detail.hpp, blahblah_private.hpp, or similar if you want to document that it's non-public.

Guidelines

So, while I'm sure everything above is all a big ball of mud so far, it's less than a page on what should take up a few chapters, so use it as a brief reference. Understanding the concepts above, however, is important. Using those, here's a short list of guidelines (but not absolute rules):

  • Always name headers consistently in a single project, such as **.h* for C and **.hpp* for C++.
  • Never include a file which is not a header.
  • Always name implementation files (which are going to be directly compiled) consistently, such as **.c* and **.cpp*.
  • Use a build system which can compile your source files automatically. make is the canonical example, but there are many alternatives. Keep it simple in simple cases. For example, make can be used its built-in rules and even without a makefile.
  • Use a build system which can generate header dependencies. Some compilers can generate this with command-line switches, such as -M, so you can make a surprisingly useful system easily.

Build Process

(Here's the tiny bit that answers your question, but you need most of the above in order to get here.)

When you build, the build system will then go through several steps, of which the important ones for this discussion are:

  1. compile each implementation file as a TU, producing an object file (**.o*, **.obj*)

    • each is compiled independently of the others, which is why each TU needs declarations and definitions
  2. link those files, along with libraries specified, into a single executable

I recommend you learn the rudiments of make, as it is popular, well-understood, and easy to get started with. However, it's an old system with several problems, and you'll want to switch to something else at some point.

Choosing a build system is almost a religious experience, like choosing an editor, except you'll have to work with more people (everyone working on the same project) and will likely be much more constrained by precedent and convention. You can use an IDE which handles the same details for you, but this has no real benefit from using a comprehensive build system instead, and you really should still know what it's doing under the hood.

File Templates

example.hpp

#ifndef EXAMPLE_INCLUDE_GUARD_60497EBE580B4F5292059C8705848F75
#define EXAMPLE_INCLUDE_GUARD_60497EBE580B4F5292059C8705848F75
// all project-specific macros for this project are prefixed "EXAMPLE_"

#include <ostream> // required headers/"modules"/libraries from the
#include <string> // stdlib, this project, and elsewhere
#include <vector>

namespace example { // main namespace for this project
template<class T>
struct TemplateExample { // for practical purposes, just put entire
void f() {} // definition of class and all methods in header
T data;
};

struct FooBar {
FooBar(); // declared
int size() const { return v.size(); } // defined (& implicitly inline)
private:
std::vector<TemplateExample<int> > v;
};

int main(std::vector<std::string> args); // declared
} // example::

#endif

example.cpp

#include "example.hpp" // include the headers "specific to" this implementation
// file first, helps make sure the header includes anything it needs (is
// independent)

#include <algorithm> // anything additional not included by the header
#include <iostream>

namespace example {
FooBar::FooBar() : v(42) {} // define ctor

int main(std::vector<std::string> args) { // define function
using namespace std; // use inside function scope, if desired, is always okay
// but using outside function scope can be problematic
cout << "doing real work now...\n"; // no std:: needed here
return 42;
}
} // example::

main.cpp

#include <iostream>
#include "example.hpp"

int main(int argc, char const** argv) try {
// do any global initialization before real main
return example::main(std::vector<std::string>(argv, argv + argc));
}
catch (std::exception& e) {
std::cerr << "[uncaught exception: " << e.what() << "]\n";
return 1; // or EXIT_FAILURE, etc.
}
catch (...) {
std::cerr << "[unknown uncaught exception]\n";
return 1; // or EXIT_FAILURE, etc.
}

How to avoid duplicate code when declaring overridden functions from interface in multiple header files?

It is not possible to avoid copy pasting void fooA() override; void fooB() override; for every derived class, under the assumption that their implementations are indeed different (as indicated by your comment // implA1 and // implA2), without resorting to macros.

NOTE: If the implementations of Derived1::fooA and Derived2::fooA are identical, then it is possible to avoid the duplication.

How to avoid duplicate code in Java when you require the same class in two separated applications?

As @Slaw says you can create a jar/library then use any build tool like maven or gradle and package the jar/library in your archive file when it is built
and here is a link for more info
https://christianlydemann.com/a-guide-to-sharing-code-between-projects/

How to avoid duplication on similar classes and similar methods?

One of the problems is that your get«classname»Result method names include the class names. That makes it impossible to make it generic without using reflection. Why don't you just rename both to getResult? You could then use generics to make the class generic.

  1. First, we define an interface which defines both getAny and setAny.

    public interface Result {
    Object getAny();
    void setAny(Object value);
    }
  2. Then we could create an implementation of Result, which is, for example, ConsultResult. You could do the same with RechargeResult.

    public class ConsultResult implements Result {
    protected Object any; // You already have a getter, so this can also be private

    public Object getAny() {
    return this.any;
    }

    public void setAny(Object value) {
    this.any = value;
    }
    }
  3. Then we could create a base class Response, which defines the getResult method. The class accepts a type argument T which must implement Result.

    public abstract class Response<T extends Result> {

    protected T result; // You already have a getter, so this can also be private

    public T getResult() {
    return this.result;
    }
    }
  4. At last, we also create our ConsultResponse class. We extend it from Response, and we provide as type argument ConsultResult.

    public class ConsultResponse extends Response<ConsultResult> {
    // The field 'result' is already present within the Response class,
    // so there is no need to include it here.
    }

Also, as GhostCat already said in the comments: what is the point of having two different inner classes in the first place? They're both the same in your example as it is currently written. You could replace them with a single base class; however, it could be that there's more members within those classes which are not shown in your example, so I left them as they were in my example.


For the validation you could do roughly the same.



Related Topics



Leave a reply



Submit