This is indeed very confusing so I set up a very small test.
$ cat CMakeLists.txt
cmake_minimum_required( VERSION 3.0 )
project(test)
add_executable( test test.cpp )
$ cat test.cpp
int main() {
}
Then I build with default options and look at the resulting options. Check that the resulting flags are empty. In the command line, cmake adds "-MT -MD" for dependency checking.
$ mkdir build && cd build
$ cmake ..
$ make VERBOSE=1
/usr/bin/c++ -MD -MT ... -c /tmp/test/test.cpp
$ grep ^CMAKE_CXX_FLAGS CMakeCache.txt
CMAKE_CXX_FLAGS:STRING=
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
Now compiling for release mode. Check that the options in the cache are exactly the same but cmake is now using the release options.
$ rm -rf *
$ cmake -DCMAKE_BUILD_TYPE=release ..
$ make VERBOSE=1
/usr/bin/c++ -O3 -DNDEBUG -MD -MT ... -c /tmp/test/test.cpp
$ grep ^CMAKE_CXX_FLAGS CMakeCache.txt
CMAKE_CXX_FLAGS:STRING=
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
Now let's change the CMAKE_CXX_FLAGS variable directly. The option has been prepended to the make command line but in the cache file everything else remains the same.
$ rm -rf *
$ cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_CXX_FLAGS="-O1" ..
$ make VERBOSE=1
/usr/bin/c++ -O1 -O3 -DNDEBUG -MD -MT ... -c /tmp/test/test.cpp
$ grep ^CMAKE_CXX_FLAGS CMakeCache.txt
CMAKE_CXX_FLAGS:STRING=-O1
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
Let's now change the CMAKE_CXX_FLAGS_RELEASE variable directly to see what happens. Looks like now we were able to replace the optimization flags with our own.
$ rm -rf *
$ cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_CXX_FLAGS_RELEASE="-O1" ..
$ make VERBOSE=1
/usr/bin/c++ -O1 -MD -MT ... -c /tmp/test/test.cpp
$ grep ^CMAKE_CXX_FLAGS CMakeCache.txt
CMAKE_CXX_FLAGS:STRING=
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
CMAKE_CXX_FLAGS_RELEASE:STRING=-O1
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
cmake also provides a CMAKE_<LANGUAGE>_FLAGS_<BUILDMODE>_INIT option. Let's see what is the impact.
$ rm -rf *
$ cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_CXX_FLAGS_RELEASE_INIT="-O1" ..
$ make VERBOSE=1
/usr/bin/c++ -O1 -O3 -DNDEBUG -MD -MT ... -c /tmp/test/test.cpp
$ grep ^CMAKE_CXX_FLAGS CMakeCache.txt
CMAKE_CXX_FLAGS:STRING=
CMAKE_CXX_FLAGS_DEBUG:STRING=-g
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG
CMAKE_CXX_FLAGS_RELEASE:STRING=-O1 -O3 -DNDEBUG
CMAKE_CXX_FLAGS_RELEASE_INIT:UNINITIALIZED=-O1
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG
So the effect of those CMAKE_CXX_FLAGS_<MODE>_INIT variables is the same as setting CMAKE_CXX_FLAGS, it prepends them to the command line, but you can configure individually for each mode - release, debug, relwithdebinfo.
So to the point of your question, setting CMAKE_CXX_FLAGS_DEBUG directly should override the other default options if you compile in debug mode.